~ubuntu-branches/ubuntu/trusty/telepathy-idle/trusty

« back to all changes in this revision

Viewing changes to .pc/0001-Don-t-use-telepathy-glib-dbus.h-with-older-telepathy.patch/src/server-tls-manager.c

  • Committer: Package Import Robot
  • Author(s): Simon McVittie
  • Date: 2013-05-01 15:52:26 UTC
  • mfrom: (1.3.6)
  • Revision ID: package-import@ubuntu.com-20130501155226-ttpmql3jetet34iu
Tags: 0.1.16-1
* New upstream release
  - adds support for interactive TLS certificate verification
    (Closes: #706270)
* Add a patch to avoid use of a telepathy-glib 0.20 header, to make
  this easy to backport to wheezy

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * server-tls-manager.c - Source for IdleServerTLSManager
 
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 "server-tls-manager.h"
 
23
 
 
24
#include <telepathy-glib/telepathy-glib.h>
 
25
#include <telepathy-glib/telepathy-glib-dbus.h>
 
26
 
 
27
#define IDLE_DEBUG_FLAG IDLE_DEBUG_TLS
 
28
#include "idle-debug.h"
 
29
#include "idle-connection.h"
 
30
#include "server-tls-channel.h"
 
31
 
 
32
#include "extensions/extensions.h"
 
33
 
 
34
static void channel_manager_iface_init (gpointer, gpointer);
 
35
 
 
36
G_DEFINE_TYPE_WITH_CODE (IdleServerTLSManager, idle_server_tls_manager,
 
37
    G_TYPE_OBJECT,
 
38
    G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
 
39
      channel_manager_iface_init));
 
40
 
 
41
enum {
 
42
  PROP_CONNECTION = 1,
 
43
  NUM_PROPERTIES
 
44
};
 
45
 
 
46
struct _IdleServerTLSManagerPrivate {
 
47
  /* Properties */
 
48
  IdleConnection *connection;
 
49
 
 
50
  /* Current operation data */
 
51
  IdleServerTLSChannel *channel;
 
52
  GSimpleAsyncResult *async_result;
 
53
 
 
54
  /* List of owned TpBaseChannel not yet closed by the client */
 
55
  GList *completed_channels;
 
56
 
 
57
  gboolean dispose_has_run;
 
58
};
 
59
 
 
60
#define chainup ((WockyTLSHandlerClass *) \
 
61
    idle_server_tls_manager_parent_class)
 
62
 
 
63
static void
 
64
idle_server_tls_manager_get_property (GObject *object,
 
65
    guint property_id,
 
66
    GValue *value,
 
67
    GParamSpec *pspec)
 
68
{
 
69
  IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
 
70
 
 
71
  switch (property_id)
 
72
    {
 
73
    case PROP_CONNECTION:
 
74
      g_value_set_object (value, self->priv->connection);
 
75
      break;
 
76
    default:
 
77
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
78
      break;
 
79
    }
 
80
}
 
81
 
 
82
static void
 
83
idle_server_tls_manager_set_property (GObject *object,
 
84
    guint property_id,
 
85
    const GValue *value,
 
86
    GParamSpec *pspec)
 
87
{
 
88
  IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
 
89
 
 
90
  switch (property_id)
 
91
    {
 
92
    case PROP_CONNECTION:
 
93
      self->priv->connection = g_value_dup_object (value);
 
94
      break;
 
95
    default:
 
96
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
97
      break;
 
98
    }
 
99
}
 
100
 
 
101
static void
 
102
close_all (IdleServerTLSManager *self)
 
103
{
 
104
  GList *l;
 
105
 
 
106
  if (self->priv->channel != NULL)
 
107
    tp_base_channel_close (TP_BASE_CHANNEL (self->priv->channel));
 
108
 
 
109
  l = self->priv->completed_channels;
 
110
  while (l != NULL)
 
111
    {
 
112
      /* use a temporary variable as the ::closed callback will delete
 
113
       * the link from the list. */
 
114
      GList *next = l->next;
 
115
 
 
116
      tp_base_channel_close (l->data);
 
117
 
 
118
      l = next;
 
119
    }
 
120
}
 
121
 
 
122
static void
 
123
connection_status_changed_cb (IdleConnection *conn,
 
124
    guint status,
 
125
    guint reason,
 
126
    gpointer user_data)
 
127
{
 
128
  IdleServerTLSManager *self = user_data;
 
129
 
 
130
  IDLE_DEBUG ("Connection status changed, now %d", status);
 
131
 
 
132
  if (status == TP_CONNECTION_STATUS_DISCONNECTED)
 
133
    {
 
134
      close_all (self);
 
135
      tp_clear_object (&self->priv->connection);
 
136
    }
 
137
}
 
138
 
 
139
static void
 
140
complete_verify (IdleServerTLSManager *self)
 
141
{
 
142
  /* Move channel to a list until a client Close() it */
 
143
  if (self->priv->channel != NULL)
 
144
    {
 
145
      self->priv->completed_channels = g_list_prepend (
 
146
          self->priv->completed_channels,
 
147
          g_object_ref (self->priv->channel));
 
148
    }
 
149
 
 
150
  g_simple_async_result_complete (self->priv->async_result);
 
151
 
 
152
  /* Reset to initial state */
 
153
  g_clear_object (&self->priv->channel);
 
154
  g_clear_object (&self->priv->async_result);
 
155
}
 
156
 
 
157
static void
 
158
server_tls_channel_closed_cb (IdleServerTLSChannel *channel,
 
159
    gpointer user_data)
 
160
{
 
161
  IdleServerTLSManager *self = user_data;
 
162
 
 
163
  IDLE_DEBUG ("Server TLS channel closed.");
 
164
 
 
165
  if (channel == self->priv->channel)
 
166
    {
 
167
      IDLE_DEBUG ("Channel closed before being handled. Failing verification");
 
168
 
 
169
      g_simple_async_result_set_error (self->priv->async_result,
 
170
          IDLE_SERVER_TLS_ERROR, 0, "TLS verification channel closed");
 
171
 
 
172
      self->priv->channel = NULL;
 
173
      complete_verify (self);
 
174
    }
 
175
  else
 
176
    {
 
177
      GList *l;
 
178
 
 
179
      l = g_list_find (self->priv->completed_channels, channel);
 
180
      g_assert (l != NULL);
 
181
 
 
182
      self->priv->completed_channels = g_list_delete_link (
 
183
          self->priv->completed_channels, l);
 
184
    }
 
185
 
 
186
  tp_channel_manager_emit_channel_closed_for_object (self,
 
187
      TP_EXPORTABLE_CHANNEL (channel));
 
188
  g_object_unref (channel);
 
189
}
 
190
 
 
191
GQuark
 
192
idle_server_tls_error_quark (void)
 
193
{
 
194
  static GQuark quark = 0;
 
195
 
 
196
  if (!quark)
 
197
    quark = g_quark_from_static_string ("server-tls-error");
 
198
 
 
199
  return quark;
 
200
}
 
201
 
 
202
static void
 
203
tls_certificate_accepted_cb (IdleTLSCertificate *certificate,
 
204
    gpointer user_data)
 
205
{
 
206
  IdleServerTLSManager *self = user_data;
 
207
 
 
208
  IDLE_DEBUG ("TLS certificate accepted");
 
209
 
 
210
  complete_verify (self);
 
211
}
 
212
 
 
213
static void
 
214
tls_certificate_rejected_cb (IdleTLSCertificate *certificate,
 
215
    GPtrArray *rejections,
 
216
    gpointer user_data)
 
217
{
 
218
  IdleServerTLSManager *self = user_data;
 
219
 
 
220
  IDLE_DEBUG ("TLS certificate rejected with rejections %p, length %u.",
 
221
      rejections, rejections->len);
 
222
 
 
223
  g_simple_async_result_set_error (self->priv->async_result,
 
224
      IDLE_SERVER_TLS_ERROR, 0, "TLS certificate rejected");
 
225
 
 
226
  complete_verify (self);
 
227
}
 
228
 
 
229
void
 
230
idle_server_tls_manager_verify_async (IdleServerTLSManager *self,
 
231
    GTlsCertificate *certificate,
 
232
    const gchar *peername,
 
233
    GAsyncReadyCallback callback,
 
234
    gpointer user_data)
 
235
{
 
236
  IdleTLSCertificate *cert;
 
237
  GSimpleAsyncResult *result;
 
238
  const gchar *identities[] = { peername, NULL };
 
239
 
 
240
  g_return_if_fail (self->priv->async_result == NULL);
 
241
 
 
242
  IDLE_DEBUG ("verify_async() called on the IdleServerTLSManager.");
 
243
 
 
244
  result = g_simple_async_result_new (G_OBJECT (self),
 
245
      callback, user_data, idle_server_tls_manager_verify_async);
 
246
 
 
247
  if (self->priv->connection == NULL)
 
248
    {
 
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);
 
254
      return;
 
255
    }
 
256
 
 
257
  self->priv->async_result = result;
 
258
 
 
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,
 
264
      NULL);
 
265
 
 
266
  g_signal_connect (self->priv->channel, "closed",
 
267
      G_CALLBACK (server_tls_channel_closed_cb), self);
 
268
 
 
269
  cert = idle_server_tls_channel_get_certificate (self->priv->channel);
 
270
 
 
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);
 
275
 
 
276
  /* emit NewChannel on the ChannelManager iface */
 
277
  tp_channel_manager_emit_new_channel (self,
 
278
      (TpExportableChannel *) self->priv->channel, NULL);
 
279
}
 
280
 
 
281
gboolean
 
282
idle_server_tls_manager_verify_finish (IdleServerTLSManager *self,
 
283
    GAsyncResult *result,
 
284
    GError **error)
 
285
{
 
286
  if (g_simple_async_result_propagate_error (
 
287
      G_SIMPLE_ASYNC_RESULT (result), error))
 
288
    return FALSE;
 
289
 
 
290
  g_return_val_if_fail (g_simple_async_result_is_valid (result,
 
291
    G_OBJECT(self), idle_server_tls_manager_verify_async), FALSE);
 
292
  return TRUE;
 
293
}
 
294
 
 
295
static void
 
296
idle_server_tls_manager_init (IdleServerTLSManager *self)
 
297
{
 
298
  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
 
299
      IDLE_TYPE_SERVER_TLS_MANAGER, IdleServerTLSManagerPrivate);
 
300
}
 
301
 
 
302
static void
 
303
idle_server_tls_manager_dispose (GObject *object)
 
304
{
 
305
  IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
 
306
 
 
307
  IDLE_DEBUG ("%p", self);
 
308
 
 
309
  if (self->priv->dispose_has_run)
 
310
    return;
 
311
 
 
312
  self->priv->dispose_has_run = TRUE;
 
313
 
 
314
  tp_clear_object (&self->priv->connection);
 
315
 
 
316
  G_OBJECT_CLASS (idle_server_tls_manager_parent_class)->dispose (object);
 
317
}
 
318
 
 
319
static void
 
320
idle_server_tls_manager_finalize (GObject *object)
 
321
{
 
322
  IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
 
323
 
 
324
  IDLE_DEBUG ("%p", self);
 
325
 
 
326
  close_all (self);
 
327
 
 
328
  G_OBJECT_CLASS (idle_server_tls_manager_parent_class)->finalize (object);
 
329
}
 
330
 
 
331
static void
 
332
idle_server_tls_manager_constructed (GObject *object)
 
333
{
 
334
  IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
 
335
  void (*chain_up) (GObject *) =
 
336
    G_OBJECT_CLASS (idle_server_tls_manager_parent_class)->constructed;
 
337
 
 
338
  if (chain_up != NULL)
 
339
    chain_up (object);
 
340
 
 
341
  IDLE_DEBUG ("Server TLS Manager constructed");
 
342
 
 
343
  tp_g_signal_connect_object (self->priv->connection, "status-changed",
 
344
      G_CALLBACK (connection_status_changed_cb), object, 0);
 
345
}
 
346
 
 
347
static void
 
348
idle_server_tls_manager_class_init (IdleServerTLSManagerClass *klass)
 
349
{
 
350
  GObjectClass *oclass = G_OBJECT_CLASS (klass);
 
351
  GParamSpec *pspec;
 
352
 
 
353
  g_type_class_add_private (klass, sizeof (IdleServerTLSManagerPrivate));
 
354
 
 
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;
 
360
 
 
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);
 
366
}
 
367
 
 
368
static void
 
369
idle_server_tls_manager_foreach_channel (TpChannelManager *manager,
 
370
    TpExportableChannelFunc func,
 
371
    gpointer user_data)
 
372
{
 
373
  IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (manager);
 
374
  GList *l;
 
375
 
 
376
  if (self->priv->channel != NULL)
 
377
    func (TP_EXPORTABLE_CHANNEL (self->priv->channel), user_data);
 
378
 
 
379
  for (l = self->priv->completed_channels; l != NULL; l = l->next)
 
380
    {
 
381
      func (l->data, user_data);
 
382
    }
 
383
}
 
384
 
 
385
static void
 
386
channel_manager_iface_init (gpointer g_iface,
 
387
    gpointer iface_data)
 
388
{
 
389
  TpChannelManagerIface *iface = g_iface;
 
390
 
 
391
  iface->foreach_channel = idle_server_tls_manager_foreach_channel;
 
392
 
 
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;
 
398
}
 
399
 
 
400
static TpConnectionStatusReason
 
401
cert_reject_reason_to_conn_reason (TpTLSCertificateRejectReason tls_reason)
 
402
{
 
403
  #define EASY_CASE(x) \
 
404
    case TP_TLS_CERTIFICATE_REJECT_REASON_ ## x: \
 
405
      return TP_CONNECTION_STATUS_REASON_CERT_ ## x;
 
406
 
 
407
  switch (tls_reason)
 
408
    {
 
409
      EASY_CASE (UNTRUSTED);
 
410
      EASY_CASE (EXPIRED);
 
411
      EASY_CASE (NOT_ACTIVATED);
 
412
      EASY_CASE (FINGERPRINT_MISMATCH);
 
413
      EASY_CASE (HOSTNAME_MISMATCH);
 
414
      EASY_CASE (SELF_SIGNED);
 
415
      EASY_CASE (REVOKED);
 
416
      EASY_CASE (INSECURE);
 
417
      EASY_CASE (LIMIT_EXCEEDED);
 
418
 
 
419
      case TP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN:
 
420
      default:
 
421
        return TP_CONNECTION_STATUS_REASON_CERT_OTHER_ERROR;
 
422
    }
 
423
 
 
424
  #undef EASY_CASE
 
425
}
 
426
 
 
427
void
 
428
idle_server_tls_manager_get_rejection_details (IdleServerTLSManager *self,
 
429
    gchar **dbus_error,
 
430
    GHashTable **details,
 
431
    TpConnectionStatusReason *reason)
 
432
{
 
433
  IdleTLSCertificate *certificate;
 
434
  GPtrArray *rejections;
 
435
  GValueArray *rejection;
 
436
  TpTLSCertificateRejectReason tls_reason;
 
437
 
 
438
  /* We probably want the rejection details of last completed operation */
 
439
  g_return_if_fail (self->priv->completed_channels != NULL);
 
440
 
 
441
  certificate = idle_server_tls_channel_get_certificate (
 
442
      self->priv->completed_channels->data);
 
443
  g_object_get (certificate,
 
444
      "rejections", &rejections,
 
445
      NULL);
 
446
 
 
447
  /* we return 'Invalid_Argument' if Reject() is called with zero
 
448
   * reasons, so if this fails something bad happened.
 
449
   */
 
450
  g_assert (rejections->len >= 1);
 
451
 
 
452
  rejection = g_ptr_array_index (rejections, 0);
 
453
 
 
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));
 
457
 
 
458
  *reason = cert_reject_reason_to_conn_reason (tls_reason);
 
459
 
 
460
  tp_clear_boxed (TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,
 
461
      &rejections);
 
462
}