2
* server-tls-manager.c - Source for IdleServerTLSManager
3
* Copyright (C) 2010 Collabora Ltd.
4
* @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
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.
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.
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
22
#include "server-tls-manager.h"
24
#include <telepathy-glib/telepathy-glib.h>
25
#include <telepathy-glib/telepathy-glib-dbus.h>
27
#define IDLE_DEBUG_FLAG IDLE_DEBUG_TLS
28
#include "idle-debug.h"
29
#include "idle-connection.h"
30
#include "server-tls-channel.h"
32
#include "extensions/extensions.h"
34
static void channel_manager_iface_init (gpointer, gpointer);
36
G_DEFINE_TYPE_WITH_CODE (IdleServerTLSManager, idle_server_tls_manager,
38
G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
39
channel_manager_iface_init));
46
struct _IdleServerTLSManagerPrivate {
48
IdleConnection *connection;
50
/* Current operation data */
51
IdleServerTLSChannel *channel;
52
GSimpleAsyncResult *async_result;
54
/* List of owned TpBaseChannel not yet closed by the client */
55
GList *completed_channels;
57
gboolean dispose_has_run;
60
#define chainup ((WockyTLSHandlerClass *) \
61
idle_server_tls_manager_parent_class)
64
idle_server_tls_manager_get_property (GObject *object,
69
IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
74
g_value_set_object (value, self->priv->connection);
77
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
83
idle_server_tls_manager_set_property (GObject *object,
88
IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
93
self->priv->connection = g_value_dup_object (value);
96
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
102
close_all (IdleServerTLSManager *self)
106
if (self->priv->channel != NULL)
107
tp_base_channel_close (TP_BASE_CHANNEL (self->priv->channel));
109
l = self->priv->completed_channels;
112
/* use a temporary variable as the ::closed callback will delete
113
* the link from the list. */
114
GList *next = l->next;
116
tp_base_channel_close (l->data);
123
connection_status_changed_cb (IdleConnection *conn,
128
IdleServerTLSManager *self = user_data;
130
IDLE_DEBUG ("Connection status changed, now %d", status);
132
if (status == TP_CONNECTION_STATUS_DISCONNECTED)
135
tp_clear_object (&self->priv->connection);
140
complete_verify (IdleServerTLSManager *self)
142
/* Move channel to a list until a client Close() it */
143
if (self->priv->channel != NULL)
145
self->priv->completed_channels = g_list_prepend (
146
self->priv->completed_channels,
147
g_object_ref (self->priv->channel));
150
g_simple_async_result_complete (self->priv->async_result);
152
/* Reset to initial state */
153
g_clear_object (&self->priv->channel);
154
g_clear_object (&self->priv->async_result);
158
server_tls_channel_closed_cb (IdleServerTLSChannel *channel,
161
IdleServerTLSManager *self = user_data;
163
IDLE_DEBUG ("Server TLS channel closed.");
165
if (channel == self->priv->channel)
167
IDLE_DEBUG ("Channel closed before being handled. Failing verification");
169
g_simple_async_result_set_error (self->priv->async_result,
170
IDLE_SERVER_TLS_ERROR, 0, "TLS verification channel closed");
172
self->priv->channel = NULL;
173
complete_verify (self);
179
l = g_list_find (self->priv->completed_channels, channel);
180
g_assert (l != NULL);
182
self->priv->completed_channels = g_list_delete_link (
183
self->priv->completed_channels, l);
186
tp_channel_manager_emit_channel_closed_for_object (self,
187
TP_EXPORTABLE_CHANNEL (channel));
188
g_object_unref (channel);
192
idle_server_tls_error_quark (void)
194
static GQuark quark = 0;
197
quark = g_quark_from_static_string ("server-tls-error");
203
tls_certificate_accepted_cb (IdleTLSCertificate *certificate,
206
IdleServerTLSManager *self = user_data;
208
IDLE_DEBUG ("TLS certificate accepted");
210
complete_verify (self);
214
tls_certificate_rejected_cb (IdleTLSCertificate *certificate,
215
GPtrArray *rejections,
218
IdleServerTLSManager *self = user_data;
220
IDLE_DEBUG ("TLS certificate rejected with rejections %p, length %u.",
221
rejections, rejections->len);
223
g_simple_async_result_set_error (self->priv->async_result,
224
IDLE_SERVER_TLS_ERROR, 0, "TLS certificate rejected");
226
complete_verify (self);
230
idle_server_tls_manager_verify_async (IdleServerTLSManager *self,
231
GTlsCertificate *certificate,
232
const gchar *peername,
233
GAsyncReadyCallback callback,
236
IdleTLSCertificate *cert;
237
GSimpleAsyncResult *result;
238
const gchar *identities[] = { peername, NULL };
240
g_return_if_fail (self->priv->async_result == NULL);
242
IDLE_DEBUG ("verify_async() called on the IdleServerTLSManager.");
244
result = g_simple_async_result_new (G_OBJECT (self),
245
callback, user_data, idle_server_tls_manager_verify_async);
247
if (self->priv->connection == NULL)
249
IDLE_DEBUG ("connection already went away; failing immediately");
250
g_simple_async_result_set_error (result, TP_ERROR, TP_ERROR_CANCELLED,
251
"The Telepathy connection has already been disconnected");
252
g_simple_async_result_complete_in_idle (result);
253
g_object_unref (result);
257
self->priv->async_result = result;
259
self->priv->channel = g_object_new (IDLE_TYPE_SERVER_TLS_CHANNEL,
260
"connection", self->priv->connection,
261
"certificate", certificate,
262
"hostname", peername,
263
"reference-identities", identities,
266
g_signal_connect (self->priv->channel, "closed",
267
G_CALLBACK (server_tls_channel_closed_cb), self);
269
cert = idle_server_tls_channel_get_certificate (self->priv->channel);
271
g_signal_connect (cert, "accepted",
272
G_CALLBACK (tls_certificate_accepted_cb), self);
273
g_signal_connect (cert, "rejected",
274
G_CALLBACK (tls_certificate_rejected_cb), self);
276
/* emit NewChannel on the ChannelManager iface */
277
tp_channel_manager_emit_new_channel (self,
278
(TpExportableChannel *) self->priv->channel, NULL);
282
idle_server_tls_manager_verify_finish (IdleServerTLSManager *self,
283
GAsyncResult *result,
286
if (g_simple_async_result_propagate_error (
287
G_SIMPLE_ASYNC_RESULT (result), error))
290
g_return_val_if_fail (g_simple_async_result_is_valid (result,
291
G_OBJECT(self), idle_server_tls_manager_verify_async), FALSE);
296
idle_server_tls_manager_init (IdleServerTLSManager *self)
298
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
299
IDLE_TYPE_SERVER_TLS_MANAGER, IdleServerTLSManagerPrivate);
303
idle_server_tls_manager_dispose (GObject *object)
305
IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
307
IDLE_DEBUG ("%p", self);
309
if (self->priv->dispose_has_run)
312
self->priv->dispose_has_run = TRUE;
314
tp_clear_object (&self->priv->connection);
316
G_OBJECT_CLASS (idle_server_tls_manager_parent_class)->dispose (object);
320
idle_server_tls_manager_finalize (GObject *object)
322
IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
324
IDLE_DEBUG ("%p", self);
328
G_OBJECT_CLASS (idle_server_tls_manager_parent_class)->finalize (object);
332
idle_server_tls_manager_constructed (GObject *object)
334
IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
335
void (*chain_up) (GObject *) =
336
G_OBJECT_CLASS (idle_server_tls_manager_parent_class)->constructed;
338
if (chain_up != NULL)
341
IDLE_DEBUG ("Server TLS Manager constructed");
343
tp_g_signal_connect_object (self->priv->connection, "status-changed",
344
G_CALLBACK (connection_status_changed_cb), object, 0);
348
idle_server_tls_manager_class_init (IdleServerTLSManagerClass *klass)
350
GObjectClass *oclass = G_OBJECT_CLASS (klass);
353
g_type_class_add_private (klass, sizeof (IdleServerTLSManagerPrivate));
355
oclass->dispose = idle_server_tls_manager_dispose;
356
oclass->finalize = idle_server_tls_manager_finalize;
357
oclass->constructed = idle_server_tls_manager_constructed;
358
oclass->set_property = idle_server_tls_manager_set_property;
359
oclass->get_property = idle_server_tls_manager_get_property;
361
pspec = g_param_spec_object ("connection", "Base connection object",
362
"base connection object that owns this manager.",
363
TP_TYPE_BASE_CONNECTION,
364
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
365
g_object_class_install_property (oclass, PROP_CONNECTION, pspec);
369
idle_server_tls_manager_foreach_channel (TpChannelManager *manager,
370
TpExportableChannelFunc func,
373
IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (manager);
376
if (self->priv->channel != NULL)
377
func (TP_EXPORTABLE_CHANNEL (self->priv->channel), user_data);
379
for (l = self->priv->completed_channels; l != NULL; l = l->next)
381
func (l->data, user_data);
386
channel_manager_iface_init (gpointer g_iface,
389
TpChannelManagerIface *iface = g_iface;
391
iface->foreach_channel = idle_server_tls_manager_foreach_channel;
393
/* these channels are not requestable. */
394
iface->ensure_channel = NULL;
395
iface->create_channel = NULL;
396
iface->request_channel = NULL;
397
iface->foreach_channel_class = NULL;
400
static TpConnectionStatusReason
401
cert_reject_reason_to_conn_reason (TpTLSCertificateRejectReason tls_reason)
403
#define EASY_CASE(x) \
404
case TP_TLS_CERTIFICATE_REJECT_REASON_ ## x: \
405
return TP_CONNECTION_STATUS_REASON_CERT_ ## x;
409
EASY_CASE (UNTRUSTED);
411
EASY_CASE (NOT_ACTIVATED);
412
EASY_CASE (FINGERPRINT_MISMATCH);
413
EASY_CASE (HOSTNAME_MISMATCH);
414
EASY_CASE (SELF_SIGNED);
416
EASY_CASE (INSECURE);
417
EASY_CASE (LIMIT_EXCEEDED);
419
case TP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN:
421
return TP_CONNECTION_STATUS_REASON_CERT_OTHER_ERROR;
428
idle_server_tls_manager_get_rejection_details (IdleServerTLSManager *self,
430
GHashTable **details,
431
TpConnectionStatusReason *reason)
433
IdleTLSCertificate *certificate;
434
GPtrArray *rejections;
435
GValueArray *rejection;
436
TpTLSCertificateRejectReason tls_reason;
438
/* We probably want the rejection details of last completed operation */
439
g_return_if_fail (self->priv->completed_channels != NULL);
441
certificate = idle_server_tls_channel_get_certificate (
442
self->priv->completed_channels->data);
443
g_object_get (certificate,
444
"rejections", &rejections,
447
/* we return 'Invalid_Argument' if Reject() is called with zero
448
* reasons, so if this fails something bad happened.
450
g_assert (rejections->len >= 1);
452
rejection = g_ptr_array_index (rejections, 0);
454
tls_reason = g_value_get_uint (g_value_array_get_nth (rejection, 0));
455
*dbus_error = g_value_dup_string (g_value_array_get_nth (rejection, 1));
456
*details = g_value_dup_boxed (g_value_array_get_nth (rejection, 2));
458
*reason = cert_reject_reason_to_conn_reason (tls_reason);
460
tp_clear_boxed (TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,