23 | 23 |
#include <telepathy-glib/telepathy-glib.h>
|
24 | 24 |
#include <telepathy-glib/telepathy-glib-dbus.h>
|
25 | 25 |
|
26 | |
#define DEBUG_FLAG IDLE_DEBUG_TLS
|
27 | |
#include "debug.h"
|
28 | |
#include "gabble/caps-channel-manager.h"
|
29 | |
#include "connection.h"
|
|
26 |
#define IDLE_DEBUG_FLAG IDLE_DEBUG_TLS
|
|
27 |
#include "idle-debug.h"
|
|
28 |
#include "idle-connection.h"
|
30 | 29 |
#include "server-tls-channel.h"
|
31 | |
#include "util.h"
|
32 | 30 |
|
33 | 31 |
#include "extensions/extensions.h"
|
34 | 32 |
|
35 | |
#include <wocky/wocky.h>
|
36 | |
|
37 | 33 |
static void channel_manager_iface_init (gpointer, gpointer);
|
38 | 34 |
|
39 | 35 |
G_DEFINE_TYPE_WITH_CODE (IdleServerTLSManager, idle_server_tls_manager,
|
40 | |
WOCKY_TYPE_TLS_HANDLER,
|
|
36 |
G_TYPE_OBJECT,
|
41 | 37 |
G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
|
42 | |
channel_manager_iface_init);
|
43 | |
G_IMPLEMENT_INTERFACE (IDLE_TYPE_CAPS_CHANNEL_MANAGER,
|
44 | |
NULL));
|
|
38 |
channel_manager_iface_init));
|
45 | 39 |
|
46 | 40 |
enum {
|
47 | 41 |
PROP_CONNECTION = 1,
|
48 | |
PROP_INTERACTIVE_TLS,
|
49 | 42 |
NUM_PROPERTIES
|
50 | 43 |
};
|
51 | 44 |
|
52 | 45 |
struct _IdleServerTLSManagerPrivate {
|
53 | 46 |
/* Properties */
|
54 | 47 |
IdleConnection *connection;
|
55 | |
gboolean interactive_tls;
|
56 | 48 |
|
57 | 49 |
/* Current operation data */
|
58 | |
gchar *peername;
|
59 | |
GStrv reference_identities;
|
60 | |
WockyTLSSession *tls_session;
|
61 | 50 |
IdleServerTLSChannel *channel;
|
62 | 51 |
GSimpleAsyncResult *async_result;
|
63 | 52 |
|
|
83 | 72 |
case PROP_CONNECTION:
|
84 | 73 |
g_value_set_object (value, self->priv->connection);
|
85 | 74 |
break;
|
86 | |
case PROP_INTERACTIVE_TLS:
|
87 | |
g_value_set_boolean (value, self->priv->interactive_tls);
|
|
75 |
default:
|
|
76 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
77 |
break;
|
|
78 |
}
|
|
79 |
}
|
|
80 |
|
|
81 |
static void
|
|
82 |
idle_server_tls_manager_set_property (GObject *object,
|
|
83 |
guint property_id,
|
|
84 |
const GValue *value,
|
|
85 |
GParamSpec *pspec)
|
|
86 |
{
|
|
87 |
IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
|
|
88 |
|
|
89 |
switch (property_id)
|
|
90 |
{
|
|
91 |
case PROP_CONNECTION:
|
|
92 |
self->priv->connection = g_value_dup_object (value);
|
88 | 93 |
break;
|
89 | 94 |
default:
|
90 | 95 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
93 | 98 |
}
|
94 | 99 |
|
95 | 100 |
static void
|
96 | |
idle_server_tls_manager_set_property (GObject *object,
|
97 | |
guint property_id,
|
98 | |
const GValue *value,
|
99 | |
GParamSpec *pspec)
|
100 | |
{
|
101 | |
IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
|
102 | |
|
103 | |
switch (property_id)
|
104 | |
{
|
105 | |
case PROP_CONNECTION:
|
106 | |
self->priv->connection = g_value_dup_object (value);
|
107 | |
break;
|
108 | |
case PROP_INTERACTIVE_TLS:
|
109 | |
self->priv->interactive_tls = g_value_get_boolean (value);
|
110 | |
break;
|
111 | |
default:
|
112 | |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
113 | |
break;
|
114 | |
}
|
115 | |
}
|
116 | |
|
117 | |
static void
|
118 | 101 |
close_all (IdleServerTLSManager *self)
|
119 | 102 |
{
|
120 | 103 |
GList *l;
|
|
143 | 126 |
{
|
144 | 127 |
IdleServerTLSManager *self = user_data;
|
145 | 128 |
|
146 | |
DEBUG ("Connection status changed, now %d", status);
|
|
129 |
IDLE_DEBUG ("Connection status changed, now %d", status);
|
147 | 130 |
|
148 | 131 |
if (status == TP_CONNECTION_STATUS_DISCONNECTED)
|
149 | 132 |
{
|
|
166 | 149 |
g_simple_async_result_complete (self->priv->async_result);
|
167 | 150 |
|
168 | 151 |
/* Reset to initial state */
|
169 | |
tp_clear_pointer (&self->priv->peername, g_free);
|
170 | |
tp_clear_pointer (&self->priv->reference_identities, g_strfreev);
|
171 | |
g_clear_object (&self->priv->tls_session);
|
172 | 152 |
g_clear_object (&self->priv->channel);
|
173 | 153 |
g_clear_object (&self->priv->async_result);
|
174 | 154 |
}
|
175 | 155 |
|
176 | 156 |
static void
|
177 | |
verify_fallback_cb (GObject *source,
|
178 | |
GAsyncResult *result,
|
179 | |
gpointer user_data)
|
180 | |
{
|
181 | |
IdleServerTLSManager *self = (IdleServerTLSManager *) source;
|
182 | |
GError *error = NULL;
|
183 | |
|
184 | |
if (!chainup->verify_finish_func (WOCKY_TLS_HANDLER (self), result, &error))
|
185 | |
g_simple_async_result_take_error (self->priv->async_result, error);
|
186 | |
|
187 | |
complete_verify (self);
|
188 | |
}
|
189 | |
|
190 | |
static void
|
191 | 157 |
server_tls_channel_closed_cb (IdleServerTLSChannel *channel,
|
192 | 158 |
gpointer user_data)
|
193 | 159 |
{
|
194 | 160 |
IdleServerTLSManager *self = user_data;
|
195 | 161 |
|
196 | |
DEBUG ("Server TLS channel closed.");
|
|
162 |
IDLE_DEBUG ("Server TLS channel closed.");
|
197 | 163 |
|
198 | 164 |
if (channel == self->priv->channel)
|
199 | 165 |
{
|
200 | |
/* fallback to the old-style non interactive TLS verification */
|
201 | |
DEBUG ("Channel closed, but unhandled, falling back...");
|
202 | |
|
203 | |
chainup->verify_async_func (WOCKY_TLS_HANDLER (self),
|
204 | |
self->priv->tls_session, self->priv->peername,
|
205 | |
self->priv->reference_identities, verify_fallback_cb, NULL);
|
206 | |
|
207 | |
self->priv->channel = NULL;
|
|
166 |
complete_verify (self);
|
208 | 167 |
}
|
209 | 168 |
else
|
210 | 169 |
{
|
|
239 | 198 |
{
|
240 | 199 |
IdleServerTLSManager *self = user_data;
|
241 | 200 |
|
242 | |
DEBUG ("TLS certificate accepted");
|
|
201 |
IDLE_DEBUG ("TLS certificate accepted");
|
243 | 202 |
|
244 | 203 |
complete_verify (self);
|
245 | 204 |
}
|
|
251 | 210 |
{
|
252 | 211 |
IdleServerTLSManager *self = user_data;
|
253 | 212 |
|
254 | |
DEBUG ("TLS certificate rejected with rejections %p, length %u.",
|
|
213 |
IDLE_DEBUG ("TLS certificate rejected with rejections %p, length %u.",
|
255 | 214 |
rejections, rejections->len);
|
256 | 215 |
|
257 | 216 |
g_simple_async_result_set_error (self->priv->async_result,
|
|
260 | 219 |
complete_verify (self);
|
261 | 220 |
}
|
262 | 221 |
|
263 | |
static void
|
264 | |
extend_string_ptr_array (GPtrArray *array,
|
265 | |
GStrv new_elements)
|
266 | |
{
|
267 | |
gint i;
|
268 | |
|
269 | |
if (new_elements != NULL)
|
270 | |
{
|
271 | |
for (i = 0; new_elements[i] != NULL; i++)
|
272 | |
{
|
273 | |
if (!tp_str_empty (new_elements[i]))
|
274 | |
g_ptr_array_add (array, g_strdup (new_elements[i]));
|
275 | |
}
|
276 | |
}
|
277 | |
}
|
278 | |
|
279 | |
static void
|
280 | |
fill_reference_identities (IdleServerTLSManager *self,
|
|
222 |
void
|
|
223 |
idle_server_tls_manager_verify_async (IdleServerTLSManager *self,
|
|
224 |
GTlsCertificate *certificate,
|
281 | 225 |
const gchar *peername,
|
282 | |
GStrv original_extra_identities)
|
283 | |
{
|
284 | |
GPtrArray *identities;
|
285 | |
gchar *connect_server = NULL;
|
286 | |
gchar *explicit_server = NULL;
|
287 | |
GStrv extra_certificate_identities = NULL;
|
288 | |
|
289 | |
g_return_if_fail (self->priv->reference_identities == NULL);
|
290 | |
|
291 | |
g_object_get (self->priv->connection,
|
292 | |
"connect-server", &connect_server,
|
293 | |
"explicit-server", &explicit_server,
|
294 | |
"extra-certificate-identities", &extra_certificate_identities,
|
295 | |
NULL);
|
296 | |
|
297 | |
identities = g_ptr_array_new ();
|
298 | |
|
299 | |
/* The peer name, i.e, the domain part of the JID */
|
300 | |
g_ptr_array_add (identities, g_strdup (peername));
|
301 | |
|
302 | |
/* The extra identities that the caller of verify_async() passed */
|
303 | |
extend_string_ptr_array (identities, original_extra_identities);
|
304 | |
|
305 | |
/* The explicitly overridden server (if in use) */
|
306 | |
if (!tp_str_empty (explicit_server) &&
|
307 | |
!tp_strdiff (connect_server, explicit_server))
|
308 | |
{
|
309 | |
g_ptr_array_add (identities, g_strdup (explicit_server));
|
310 | |
}
|
311 | |
|
312 | |
/* Extra identities added to the account as a result of user choices */
|
313 | |
extend_string_ptr_array (identities, extra_certificate_identities);
|
314 | |
|
315 | |
/* Null terminate, since this is a gchar** */
|
316 | |
g_ptr_array_add (identities, NULL);
|
317 | |
|
318 | |
self->priv->reference_identities = (GStrv) g_ptr_array_free (identities,
|
319 | |
FALSE);
|
320 | |
|
321 | |
g_strfreev (extra_certificate_identities);
|
322 | |
g_free (explicit_server);
|
323 | |
g_free (connect_server);
|
324 | |
}
|
325 | |
|
326 | |
static void
|
327 | |
idle_server_tls_manager_verify_async (WockyTLSHandler *handler,
|
328 | |
WockyTLSSession *tls_session,
|
329 | |
const gchar *peername,
|
330 | |
GStrv extra_identities,
|
331 | 226 |
GAsyncReadyCallback callback,
|
332 | 227 |
gpointer user_data)
|
333 | 228 |
{
|
334 | |
IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (handler);
|
335 | |
IdleTLSCertificate *certificate;
|
|
229 |
IdleTLSCertificate *cert;
|
336 | 230 |
GSimpleAsyncResult *result;
|
|
231 |
const gchar *identities[] = { peername, NULL };
|
337 | 232 |
|
338 | 233 |
g_return_if_fail (self->priv->async_result == NULL);
|
339 | 234 |
|
340 | |
DEBUG ("verify_async() called on the IdleServerTLSManager.");
|
|
235 |
IDLE_DEBUG ("verify_async() called on the IdleServerTLSManager.");
|
341 | 236 |
|
342 | 237 |
result = g_simple_async_result_new (G_OBJECT (self),
|
343 | 238 |
callback, user_data, idle_server_tls_manager_verify_async);
|
344 | 239 |
|
345 | 240 |
if (self->priv->connection == NULL)
|
346 | 241 |
{
|
347 | |
DEBUG ("connection already went away; failing immediately");
|
|
242 |
IDLE_DEBUG ("connection already went away; failing immediately");
|
348 | 243 |
g_simple_async_result_set_error (result, TP_ERROR, TP_ERROR_CANCELLED,
|
349 | 244 |
"The Telepathy connection has already been disconnected");
|
350 | 245 |
g_simple_async_result_complete_in_idle (result);
|
|
354 | 249 |
|
355 | 250 |
self->priv->async_result = result;
|
356 | 251 |
|
357 | |
fill_reference_identities (self, peername, extra_identities);
|
358 | |
|
359 | |
if (!self->priv->interactive_tls)
|
360 | |
{
|
361 | |
DEBUG ("ignore-ssl-errors is set, fallback to non-interactive "
|
362 | |
"verification.");
|
363 | |
|
364 | |
chainup->verify_async_func (WOCKY_TLS_HANDLER (self), tls_session,
|
365 | |
peername, self->priv->reference_identities, verify_fallback_cb, NULL);
|
366 | |
|
367 | |
return;
|
368 | |
}
|
369 | |
|
370 | |
self->priv->tls_session = g_object_ref (tls_session);
|
371 | |
self->priv->peername = g_strdup (peername);
|
372 | |
|
373 | 252 |
self->priv->channel = g_object_new (IDLE_TYPE_SERVER_TLS_CHANNEL,
|
374 | 253 |
"connection", self->priv->connection,
|
375 | |
"tls-session", tls_session,
|
|
254 |
"certificate", certificate,
|
376 | 255 |
"hostname", peername,
|
377 | |
"reference-identities", self->priv->reference_identities,
|
|
256 |
"reference-identities", identities,
|
378 | 257 |
NULL);
|
379 | 258 |
|
380 | 259 |
g_signal_connect (self->priv->channel, "closed",
|
381 | 260 |
G_CALLBACK (server_tls_channel_closed_cb), self);
|
382 | 261 |
|
383 | |
certificate = idle_server_tls_channel_get_certificate (self->priv->channel);
|
384 | |
|
385 | |
g_signal_connect (certificate, "accepted",
|
|
262 |
cert = idle_server_tls_channel_get_certificate (self->priv->channel);
|
|
263 |
|
|
264 |
g_signal_connect (cert, "accepted",
|
386 | 265 |
G_CALLBACK (tls_certificate_accepted_cb), self);
|
387 | |
g_signal_connect (certificate, "rejected",
|
|
266 |
g_signal_connect (cert, "rejected",
|
388 | 267 |
G_CALLBACK (tls_certificate_rejected_cb), self);
|
389 | 268 |
|
390 | 269 |
/* emit NewChannel on the ChannelManager iface */
|
|
392 | 271 |
(TpExportableChannel *) self->priv->channel, NULL);
|
393 | 272 |
}
|
394 | 273 |
|
395 | |
static gboolean
|
396 | |
idle_server_tls_manager_verify_finish (WockyTLSHandler *self,
|
|
274 |
gboolean
|
|
275 |
idle_server_tls_manager_verify_finish (IdleServerTLSManager *self,
|
397 | 276 |
GAsyncResult *result,
|
398 | 277 |
GError **error)
|
399 | 278 |
{
|
400 | |
wocky_implement_finish_void (self, idle_server_tls_manager_verify_async);
|
|
279 |
if (g_simple_async_result_propagate_error (
|
|
280 |
G_SIMPLE_ASYNC_RESULT (result), error))
|
|
281 |
return FALSE;
|
|
282 |
|
|
283 |
g_return_val_if_fail (g_simple_async_result_is_valid (result,
|
|
284 |
G_OBJECT(self), idle_server_tls_manager_verify_async), FALSE);
|
|
285 |
return TRUE;
|
401 | 286 |
}
|
402 | 287 |
|
403 | 288 |
static void
|
|
412 | 297 |
{
|
413 | 298 |
IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
|
414 | 299 |
|
415 | |
DEBUG ("%p", self);
|
|
300 |
IDLE_DEBUG ("%p", self);
|
416 | 301 |
|
417 | 302 |
if (self->priv->dispose_has_run)
|
418 | 303 |
return;
|
419 | 304 |
|
420 | 305 |
self->priv->dispose_has_run = TRUE;
|
421 | 306 |
|
422 | |
tp_clear_object (&self->priv->tls_session);
|
423 | 307 |
tp_clear_object (&self->priv->connection);
|
424 | 308 |
|
425 | 309 |
G_OBJECT_CLASS (idle_server_tls_manager_parent_class)->dispose (object);
|
|
430 | 314 |
{
|
431 | 315 |
IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
|
432 | 316 |
|
433 | |
DEBUG ("%p", self);
|
|
317 |
IDLE_DEBUG ("%p", self);
|
434 | 318 |
|
435 | 319 |
close_all (self);
|
436 | |
|
437 | |
g_free (self->priv->peername);
|
438 | |
g_strfreev (self->priv->reference_identities);
|
439 | 320 |
|
440 | 321 |
G_OBJECT_CLASS (idle_server_tls_manager_parent_class)->finalize (object);
|
441 | 322 |
}
|
|
450 | 331 |
if (chain_up != NULL)
|
451 | 332 |
chain_up (object);
|
452 | 333 |
|
453 | |
DEBUG ("Server TLS Manager constructed");
|
454 | |
|
455 | |
idle_signal_connect_weak (self->priv->connection, "status-changed",
|
456 | |
G_CALLBACK (connection_status_changed_cb), object);
|
|
334 |
IDLE_DEBUG ("Server TLS Manager constructed");
|
|
335 |
|
|
336 |
tp_g_signal_connect_object (self->priv->connection, "status-changed",
|
|
337 |
G_CALLBACK (connection_status_changed_cb), object, 0);
|
457 | 338 |
}
|
458 | 339 |
|
459 | 340 |
static void
|
460 | 341 |
idle_server_tls_manager_class_init (IdleServerTLSManagerClass *klass)
|
461 | 342 |
{
|
462 | 343 |
GObjectClass *oclass = G_OBJECT_CLASS (klass);
|
463 | |
WockyTLSHandlerClass *hclass = WOCKY_TLS_HANDLER_CLASS (klass);
|
464 | 344 |
GParamSpec *pspec;
|
465 | 345 |
|
466 | 346 |
g_type_class_add_private (klass, sizeof (IdleServerTLSManagerPrivate));
|
|
471 | 351 |
oclass->set_property = idle_server_tls_manager_set_property;
|
472 | 352 |
oclass->get_property = idle_server_tls_manager_get_property;
|
473 | 353 |
|
474 | |
hclass->verify_async_func = idle_server_tls_manager_verify_async;
|
475 | |
hclass->verify_finish_func = idle_server_tls_manager_verify_finish;
|
476 | |
|
477 | |
pspec = g_param_spec_object ("connection", "IdleConnection object",
|
478 | |
"Idle connection object that owns this manager.",
|
479 | |
IDLE_TYPE_CONNECTION,
|
|
354 |
pspec = g_param_spec_object ("connection", "Base connection object",
|
|
355 |
"base connection object that owns this manager.",
|
|
356 |
TP_TYPE_BASE_CONNECTION,
|
480 | 357 |
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
481 | 358 |
g_object_class_install_property (oclass, PROP_CONNECTION, pspec);
|
482 | |
|
483 | |
pspec = g_param_spec_boolean ("interactive-tls", "Interactive TLS setting",
|
484 | |
"Whether interactive TLS certificate verification is enabled.",
|
485 | |
FALSE,
|
486 | |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
487 | |
g_object_class_install_property (oclass, PROP_INTERACTIVE_TLS, pspec);
|
488 | 359 |
}
|
489 | 360 |
|
490 | 361 |
static void
|