~ubuntu-branches/ubuntu/wily/evolution-data-server/wily

« back to all changes in this revision

Viewing changes to libebackend/e-authentication-mediator.c

  • Committer: Package Import Robot
  • Author(s): Iain Lane
  • Date: 2015-07-20 13:34:59 UTC
  • mfrom: (1.1.126) (1.2.48 sid)
  • Revision ID: package-import@ubuntu.com-20150720133459-g6y46hnu5ewtoz08
Tags: 3.16.4-0ubuntu2
debian/patches/0001-Bug-752373-Monthly-events-do-not-recur-correctly.patch:
Cherry-pick patch from upstream to fix events not recurring correctly.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * e-authentication-mediator.c
3
 
 *
4
 
 * This library is free software you can redistribute it and/or modify it
5
 
 * under the terms of the GNU Lesser General Public License as published by
6
 
 * the Free Software Foundation.
7
 
 *
8
 
 * This library is distributed in the hope that it will be useful, but
9
 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
 
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11
 
 * for more details.
12
 
 *
13
 
 * You should have received a copy of the GNU Lesser General Public License
14
 
 * along with this library; if not, see <http://www.gnu.org/licenses/>.
15
 
 *
16
 
 */
17
 
 
18
 
/**
19
 
 * SECTION: e-authentication-mediator
20
 
 * @include: libebackend/libebackend.h
21
 
 * @short_description: Authenticator proxy for remote clients
22
 
 *
23
 
 * #EAuthenticationMediator runs on the registry D-Bus service.  It mediates
24
 
 * authentication attempts between the client requesting authentication and
25
 
 * the server-side #EAuthenticationSession interacting with the user and/or
26
 
 * secret service.  It implements the #ESourceAuthenticator interface and
27
 
 * securely transmits passwords to a remote #ESourceRegistry over D-Bus.
28
 
 **/
29
 
 
30
 
#include "e-authentication-mediator.h"
31
 
 
32
 
/* XXX Yeah, yeah... */
33
 
#define GCR_API_SUBJECT_TO_CHANGE
34
 
 
35
 
#include <config.h>
36
 
#include <glib/gi18n-lib.h>
37
 
#include <gcr/gcr-base.h>
38
 
 
39
 
/* Private D-Bus classes. */
40
 
#include <e-dbus-authenticator.h>
41
 
 
42
 
#define E_AUTHENTICATION_MEDIATOR_GET_PRIVATE(obj) \
43
 
        (G_TYPE_INSTANCE_GET_PRIVATE \
44
 
        ((obj), E_TYPE_AUTHENTICATION_MEDIATOR, EAuthenticationMediatorPrivate))
45
 
 
46
 
/* How long should clients have to respond before timing out the
47
 
 * authentication session?  Need to balance allowing adequate time
48
 
 * without blocking other requests too long if a client gets stuck. */
49
 
#define INACTIVITY_TIMEOUT (2 * 60)  /* in seconds */
50
 
 
51
 
typedef struct _AsyncContext AsyncContext;
52
 
typedef struct _ThreadClosure ThreadClosure;
53
 
 
54
 
struct _EAuthenticationMediatorPrivate {
55
 
        GDBusConnection *connection;
56
 
        EDBusAuthenticator *dbus_interface;
57
 
        GcrSecretExchange *secret_exchange;
58
 
        gchar *object_path;
59
 
        gchar *sender;
60
 
 
61
 
        ThreadClosure *thread_closure;
62
 
 
63
 
        GMutex shared_data_lock;
64
 
 
65
 
        GQueue try_password_queue;
66
 
        GQueue wait_for_client_queue;
67
 
 
68
 
        gboolean client_is_ready;
69
 
        gboolean client_cancelled;
70
 
        gboolean client_vanished;
71
 
 
72
 
        guint watcher_id;
73
 
};
74
 
 
75
 
struct _AsyncContext {
76
 
        /* These point into the EAuthenticationMediatorPrivate
77
 
         * struct.  Do not free them in async_context_free(). */
78
 
        GMutex *shared_data_lock;
79
 
        GQueue *operation_queue;
80
 
 
81
 
        GCancellable *cancellable;
82
 
        gulong cancel_id;
83
 
        guint timeout_id;
84
 
};
85
 
 
86
 
struct _ThreadClosure {
87
 
        volatile gint ref_count;
88
 
        GWeakRef mediator;
89
 
        GMainContext *main_context;
90
 
        GMainLoop *main_loop;
91
 
        GCond main_loop_cond;
92
 
        GMutex main_loop_mutex;
93
 
        GError *export_error;
94
 
};
95
 
 
96
 
enum {
97
 
        PROP_0,
98
 
        PROP_CONNECTION,
99
 
        PROP_OBJECT_PATH,
100
 
        PROP_SENDER
101
 
};
102
 
 
103
 
/* Forward Declarations */
104
 
static void     e_authentication_mediator_initable_init
105
 
                                (GInitableIface *iface);
106
 
static void     e_authentication_mediator_interface_init
107
 
                                (ESourceAuthenticatorInterface *iface);
108
 
 
109
 
G_DEFINE_TYPE_WITH_CODE (
110
 
        EAuthenticationMediator,
111
 
        e_authentication_mediator,
112
 
        G_TYPE_OBJECT,
113
 
        G_IMPLEMENT_INTERFACE (
114
 
                G_TYPE_INITABLE,
115
 
                e_authentication_mediator_initable_init)
116
 
        G_IMPLEMENT_INTERFACE (
117
 
                E_TYPE_SOURCE_AUTHENTICATOR,
118
 
                e_authentication_mediator_interface_init))
119
 
 
120
 
static void
121
 
async_context_free (AsyncContext *async_context)
122
 
{
123
 
        if (async_context->cancellable != NULL) {
124
 
                g_cancellable_disconnect (
125
 
                        async_context->cancellable,
126
 
                        async_context->cancel_id);
127
 
                g_object_unref (async_context->cancellable);
128
 
        }
129
 
 
130
 
        if (async_context->timeout_id > 0)
131
 
                g_source_remove (async_context->timeout_id);
132
 
 
133
 
        g_slice_free (AsyncContext, async_context);
134
 
}
135
 
 
136
 
static ThreadClosure *
137
 
thread_closure_new (EAuthenticationMediator *mediator)
138
 
{
139
 
        ThreadClosure *closure;
140
 
 
141
 
        closure = g_slice_new0 (ThreadClosure);
142
 
        closure->ref_count = 1;
143
 
        g_weak_ref_init (&closure->mediator, mediator);
144
 
        closure->main_context = g_main_context_new ();
145
 
        /* It's important to pass 'is_running=FALSE' here because
146
 
         * we wait for the main loop to start running as a way of
147
 
         * synchronizing with the manager thread. */
148
 
        closure->main_loop = g_main_loop_new (closure->main_context, FALSE);
149
 
        g_cond_init (&closure->main_loop_cond);
150
 
        g_mutex_init (&closure->main_loop_mutex);
151
 
 
152
 
        return closure;
153
 
}
154
 
 
155
 
static ThreadClosure *
156
 
thread_closure_ref (ThreadClosure *closure)
157
 
{
158
 
        g_return_val_if_fail (closure != NULL, NULL);
159
 
        g_return_val_if_fail (closure->ref_count > 0, NULL);
160
 
 
161
 
        g_atomic_int_inc (&closure->ref_count);
162
 
 
163
 
        return closure;
164
 
}
165
 
 
166
 
static void
167
 
thread_closure_unref (ThreadClosure *closure)
168
 
{
169
 
        g_return_if_fail (closure != NULL);
170
 
        g_return_if_fail (closure->ref_count > 0);
171
 
 
172
 
        if (g_atomic_int_dec_and_test (&closure->ref_count)) {
173
 
                g_weak_ref_clear (&closure->mediator);
174
 
                g_main_context_unref (closure->main_context);
175
 
                g_main_loop_unref (closure->main_loop);
176
 
                g_cond_clear (&closure->main_loop_cond);
177
 
                g_mutex_clear (&closure->main_loop_mutex);
178
 
 
179
 
                g_slice_free (ThreadClosure, closure);
180
 
        }
181
 
}
182
 
 
183
 
static void
184
 
authentication_mediator_name_vanished_cb (GDBusConnection *connection,
185
 
                                          const gchar *name,
186
 
                                          gpointer user_data)
187
 
{
188
 
        EAuthenticationMediator *mediator;
189
 
        GSimpleAsyncResult *simple;
190
 
        GQueue *queue;
191
 
 
192
 
        mediator = E_AUTHENTICATION_MEDIATOR (user_data);
193
 
 
194
 
        g_mutex_lock (&mediator->priv->shared_data_lock);
195
 
 
196
 
        mediator->priv->client_vanished = TRUE;
197
 
 
198
 
        queue = &mediator->priv->try_password_queue;
199
 
 
200
 
        /* Notify any unfinished try_password() operations. */
201
 
        while ((simple = g_queue_pop_head (queue)) != NULL) {
202
 
                g_simple_async_result_set_error (
203
 
                        simple, G_IO_ERROR, G_IO_ERROR_CANCELLED,
204
 
                        "%s", _("Bus name vanished (client terminated?)"));
205
 
                g_simple_async_result_complete_in_idle (simple);
206
 
                g_object_unref (simple);
207
 
        }
208
 
 
209
 
        queue = &mediator->priv->wait_for_client_queue;
210
 
 
211
 
        /* Notify any unfinished wait_for_client() operations. */
212
 
        while ((simple = g_queue_pop_head (queue)) != NULL) {
213
 
                g_simple_async_result_set_error (
214
 
                        simple, G_IO_ERROR, G_IO_ERROR_CANCELLED,
215
 
                        "%s", _("Bus name vanished (client terminated?)"));
216
 
                g_simple_async_result_complete_in_idle (simple);
217
 
                g_object_unref (simple);
218
 
        }
219
 
 
220
 
        g_bus_unwatch_name (mediator->priv->watcher_id);
221
 
        mediator->priv->watcher_id = 0;
222
 
 
223
 
        g_mutex_unlock (&mediator->priv->shared_data_lock);
224
 
}
225
 
 
226
 
static void
227
 
authentication_mediator_cancelled_cb (GCancellable *cancellable,
228
 
                                      gpointer user_data)
229
 
{
230
 
        GSimpleAsyncResult *simple;
231
 
        AsyncContext *async_context;
232
 
 
233
 
        simple = G_SIMPLE_ASYNC_RESULT (user_data);
234
 
        async_context = g_simple_async_result_get_op_res_gpointer (simple);
235
 
 
236
 
        g_mutex_lock (async_context->shared_data_lock);
237
 
 
238
 
        /* Because we called g_simple_async_result_set_check_cancellable(),
239
 
         * g_simple_async_result_propagate_error() will automatically set a
240
 
         * cancelled error so we don't need to explicitly set one here. */
241
 
        if (g_queue_remove (async_context->operation_queue, simple)) {
242
 
                g_simple_async_result_complete_in_idle (simple);
243
 
                g_object_unref (simple);
244
 
        }
245
 
 
246
 
        g_mutex_unlock (async_context->shared_data_lock);
247
 
}
248
 
 
249
 
static gboolean
250
 
authentication_mediator_timeout_cb (gpointer user_data)
251
 
{
252
 
        GSimpleAsyncResult *simple;
253
 
        AsyncContext *async_context;
254
 
 
255
 
        simple = G_SIMPLE_ASYNC_RESULT (user_data);
256
 
        async_context = g_simple_async_result_get_op_res_gpointer (simple);
257
 
 
258
 
        g_mutex_lock (async_context->shared_data_lock);
259
 
 
260
 
        if (g_queue_remove (async_context->operation_queue, simple)) {
261
 
                g_simple_async_result_set_error (
262
 
                        simple, G_IO_ERROR, G_IO_ERROR_TIMED_OUT,
263
 
                        "%s", _("No response from client"));
264
 
                g_simple_async_result_complete_in_idle (simple);
265
 
                g_object_unref (simple);
266
 
        }
267
 
 
268
 
        g_mutex_unlock (async_context->shared_data_lock);
269
 
 
270
 
        return FALSE;
271
 
}
272
 
 
273
 
static gboolean
274
 
authentication_mediator_handle_ready (EDBusAuthenticator *dbus_interface,
275
 
                                      GDBusMethodInvocation *invocation,
276
 
                                      const gchar *encrypted_key,
277
 
                                      ThreadClosure *closure)
278
 
{
279
 
        EAuthenticationMediator *mediator;
280
 
        GcrSecretExchange *secret_exchange;
281
 
        GSimpleAsyncResult *simple;
282
 
        GQueue *queue;
283
 
 
284
 
        mediator = g_weak_ref_get (&closure->mediator);
285
 
        g_return_val_if_fail (mediator != NULL, FALSE);
286
 
 
287
 
        g_mutex_lock (&mediator->priv->shared_data_lock);
288
 
 
289
 
        mediator->priv->client_is_ready = TRUE;
290
 
 
291
 
        secret_exchange = mediator->priv->secret_exchange;
292
 
        gcr_secret_exchange_receive (secret_exchange, encrypted_key);
293
 
 
294
 
        queue = &mediator->priv->wait_for_client_queue;
295
 
 
296
 
        /* Notify any unfinished wait_for_client() operations. */
297
 
        while ((simple = g_queue_pop_head (queue)) != NULL) {
298
 
                g_simple_async_result_complete_in_idle (simple);
299
 
                g_object_unref (simple);
300
 
        }
301
 
 
302
 
        g_mutex_unlock (&mediator->priv->shared_data_lock);
303
 
 
304
 
        e_dbus_authenticator_complete_ready (dbus_interface, invocation);
305
 
 
306
 
        g_object_unref (mediator);
307
 
 
308
 
        return TRUE;
309
 
}
310
 
 
311
 
static gboolean
312
 
authentication_mediator_handle_cancel (EDBusAuthenticator *dbus_interface,
313
 
                                       GDBusMethodInvocation *invocation,
314
 
                                       ThreadClosure *closure)
315
 
{
316
 
        EAuthenticationMediator *mediator;
317
 
        GSimpleAsyncResult *simple;
318
 
        GQueue *queue;
319
 
 
320
 
        mediator = g_weak_ref_get (&closure->mediator);
321
 
        g_return_val_if_fail (mediator != NULL, FALSE);
322
 
 
323
 
        g_mutex_lock (&mediator->priv->shared_data_lock);
324
 
 
325
 
        mediator->priv->client_cancelled = TRUE;
326
 
 
327
 
        queue = &mediator->priv->try_password_queue;
328
 
 
329
 
        /* Notify any unfinished try_password() operations. */
330
 
        while ((simple = g_queue_pop_head (queue)) != NULL) {
331
 
                g_simple_async_result_set_error (
332
 
                        simple, G_IO_ERROR, G_IO_ERROR_CANCELLED,
333
 
                        "%s", _("Client cancelled the operation"));
334
 
                g_simple_async_result_complete_in_idle (simple);
335
 
                g_object_unref (simple);
336
 
        }
337
 
 
338
 
        queue = &mediator->priv->wait_for_client_queue;
339
 
 
340
 
        /* Notify any unfinished wait_for_client() operations. */
341
 
        while ((simple = g_queue_pop_head (queue)) != NULL) {
342
 
                g_simple_async_result_set_error (
343
 
                        simple, G_IO_ERROR, G_IO_ERROR_CANCELLED,
344
 
                        "%s", _("Client cancelled the operation"));
345
 
                g_simple_async_result_complete_in_idle (simple);
346
 
                g_object_unref (simple);
347
 
        }
348
 
 
349
 
        g_mutex_unlock (&mediator->priv->shared_data_lock);
350
 
 
351
 
        e_dbus_authenticator_complete_cancel (dbus_interface, invocation);
352
 
 
353
 
        g_object_unref (mediator);
354
 
 
355
 
        return TRUE;
356
 
}
357
 
 
358
 
static gboolean
359
 
authentication_mediator_handle_accepted (EDBusAuthenticator *dbus_interface,
360
 
                                         GDBusMethodInvocation *invocation,
361
 
                                         ThreadClosure *closure)
362
 
{
363
 
        EAuthenticationMediator *mediator;
364
 
        GSimpleAsyncResult *simple;
365
 
        GQueue *queue;
366
 
 
367
 
        mediator = g_weak_ref_get (&closure->mediator);
368
 
        g_return_val_if_fail (mediator != NULL, FALSE);
369
 
 
370
 
        g_mutex_lock (&mediator->priv->shared_data_lock);
371
 
 
372
 
        queue = &mediator->priv->try_password_queue;
373
 
 
374
 
        if (g_queue_is_empty (queue))
375
 
                g_warning ("%s: Unexpected 'accepted' signal", G_STRFUNC);
376
 
 
377
 
        /* Notify any unfinished try_password() operations. */
378
 
        while ((simple = g_queue_pop_head (queue)) != NULL) {
379
 
                g_simple_async_result_complete_in_idle (simple);
380
 
                g_object_unref (simple);
381
 
        }
382
 
 
383
 
        g_mutex_unlock (&mediator->priv->shared_data_lock);
384
 
 
385
 
        e_dbus_authenticator_complete_accepted (dbus_interface, invocation);
386
 
 
387
 
        g_object_unref (mediator);
388
 
 
389
 
        return TRUE;
390
 
}
391
 
 
392
 
static gboolean
393
 
authentication_mediator_handle_rejected (EDBusAuthenticator *dbus_interface,
394
 
                                         GDBusMethodInvocation *invocation,
395
 
                                         ThreadClosure *closure)
396
 
{
397
 
        EAuthenticationMediator *mediator;
398
 
        GSimpleAsyncResult *simple;
399
 
        GQueue *queue;
400
 
 
401
 
        mediator = g_weak_ref_get (&closure->mediator);
402
 
        g_return_val_if_fail (mediator != NULL, FALSE);
403
 
 
404
 
        g_mutex_lock (&mediator->priv->shared_data_lock);
405
 
 
406
 
        queue = &mediator->priv->try_password_queue;
407
 
 
408
 
        if (g_queue_is_empty (queue))
409
 
                g_warning ("%s: Unexpected 'rejected' signal", G_STRFUNC);
410
 
 
411
 
        /* Notify any unfinished try_password() operations. */
412
 
        while ((simple = g_queue_pop_head (queue)) != NULL) {
413
 
                g_simple_async_result_set_error (
414
 
                        simple, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
415
 
                        "%s", _("Client reports password was rejected"));
416
 
                g_simple_async_result_complete_in_idle (simple);
417
 
                g_object_unref (simple);
418
 
        }
419
 
 
420
 
        g_mutex_unlock (&mediator->priv->shared_data_lock);
421
 
 
422
 
        e_dbus_authenticator_complete_rejected (dbus_interface, invocation);
423
 
 
424
 
        g_object_unref (mediator);
425
 
 
426
 
        return TRUE;
427
 
}
428
 
 
429
 
static gboolean
430
 
authentication_mediator_authenticator_running (gpointer data)
431
 
{
432
 
        ThreadClosure *closure = data;
433
 
 
434
 
        g_mutex_lock (&closure->main_loop_mutex);
435
 
        g_cond_broadcast (&closure->main_loop_cond);
436
 
        g_mutex_unlock (&closure->main_loop_mutex);
437
 
 
438
 
        return FALSE;
439
 
}
440
 
 
441
 
static gpointer
442
 
authentication_mediator_authenticator_thread (gpointer data)
443
 
{
444
 
        EAuthenticationMediator *mediator;
445
 
        GDBusInterfaceSkeleton *dbus_interface;
446
 
        GDBusConnection *connection;
447
 
        ThreadClosure *closure = data;
448
 
        GSource *idle_source;
449
 
        const gchar *object_path;
450
 
        gulong handle_ready_id;
451
 
        gulong handle_cancel_id;
452
 
        gulong handle_accepted_id;
453
 
        gulong handle_rejected_id;
454
 
 
455
 
        /* This is similar to the manager thread in ESourceRegistry.
456
 
         * GDBusInterfaceSkeleton will emit "handle-*" signals from
457
 
         * the GMainContext that was the thread-default at the time
458
 
         * the interface was exported.  So we export the interface
459
 
         * from an isolated thread to prevent its signal emissions
460
 
         * from being inhibited by someone pushing a thread-default
461
 
         * GMainContext. */
462
 
 
463
 
        mediator = g_weak_ref_get (&closure->mediator);
464
 
        g_return_val_if_fail (mediator != NULL, NULL);
465
 
 
466
 
        /* Keep our own reference to the GDBusInterfaceSkeleton so
467
 
         * we can clean up signals after the mediator is disposed. */
468
 
        dbus_interface = g_object_ref (mediator->priv->dbus_interface);
469
 
 
470
 
        connection = e_authentication_mediator_get_connection (mediator);
471
 
        object_path = e_authentication_mediator_get_object_path (mediator);
472
 
 
473
 
        /* This becomes the GMainContext from which the Authenticator
474
 
         * interface will emit method invocation signals.  Make it the
475
 
         * thread-default context for this thread before exporting the
476
 
         * interface. */
477
 
 
478
 
        g_main_context_push_thread_default (closure->main_context);
479
 
 
480
 
        /* Listen for method invocations. */
481
 
 
482
 
        handle_ready_id = g_signal_connect_data (
483
 
                dbus_interface, "handle-ready",
484
 
                G_CALLBACK (authentication_mediator_handle_ready),
485
 
                thread_closure_ref (closure),
486
 
                (GClosureNotify) thread_closure_unref, 0);
487
 
 
488
 
        handle_cancel_id = g_signal_connect_data (
489
 
                dbus_interface, "handle-cancel",
490
 
                G_CALLBACK (authentication_mediator_handle_cancel),
491
 
                thread_closure_ref (closure),
492
 
                (GClosureNotify) thread_closure_unref, 0);
493
 
 
494
 
        handle_accepted_id = g_signal_connect_data (
495
 
                dbus_interface, "handle-accepted",
496
 
                G_CALLBACK (authentication_mediator_handle_accepted),
497
 
                thread_closure_ref (closure),
498
 
                (GClosureNotify) thread_closure_unref, 0);
499
 
 
500
 
        handle_rejected_id = g_signal_connect_data (
501
 
                dbus_interface, "handle-rejected",
502
 
                G_CALLBACK (authentication_mediator_handle_rejected),
503
 
                thread_closure_ref (closure),
504
 
                (GClosureNotify) thread_closure_unref, 0);
505
 
 
506
 
        /* Export the Authenticator interface. */
507
 
 
508
 
        g_dbus_interface_skeleton_export (
509
 
                dbus_interface, connection, object_path, &closure->export_error);
510
 
 
511
 
        /* Schedule a one-time idle callback to broadcast through a
512
 
         * condition variable that our main loop is up and running. */
513
 
 
514
 
        idle_source = g_idle_source_new ();
515
 
        g_source_set_callback (
516
 
                idle_source,
517
 
                authentication_mediator_authenticator_running,
518
 
                closure, (GDestroyNotify) NULL);
519
 
        g_source_attach (idle_source, closure->main_context);
520
 
        g_source_unref (idle_source);
521
 
 
522
 
        /* Unreference this before starting the main loop since
523
 
         * the mediator's dispose() method tells us when to quit.
524
 
         * If we don't do this then dispose() will never run. */
525
 
        g_object_unref (mediator);
526
 
 
527
 
        /* Now we mostly idle here until authentication is complete. */
528
 
 
529
 
        g_main_loop_run (closure->main_loop);
530
 
 
531
 
        /* Clean up and exit. */
532
 
 
533
 
        g_signal_handler_disconnect (dbus_interface, handle_ready_id);
534
 
        g_signal_handler_disconnect (dbus_interface, handle_cancel_id);
535
 
        g_signal_handler_disconnect (dbus_interface, handle_accepted_id);
536
 
        g_signal_handler_disconnect (dbus_interface, handle_rejected_id);
537
 
 
538
 
        g_main_context_pop_thread_default (closure->main_context);
539
 
 
540
 
        g_object_unref (dbus_interface);
541
 
 
542
 
        thread_closure_unref (closure);
543
 
 
544
 
        return NULL;
545
 
}
546
 
 
547
 
static void
548
 
authentication_mediator_set_connection (EAuthenticationMediator *mediator,
549
 
                                        GDBusConnection *connection)
550
 
{
551
 
        g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
552
 
        g_return_if_fail (mediator->priv->connection == NULL);
553
 
 
554
 
        mediator->priv->connection = g_object_ref (connection);
555
 
}
556
 
 
557
 
static void
558
 
authentication_mediator_set_object_path (EAuthenticationMediator *mediator,
559
 
                                         const gchar *object_path)
560
 
{
561
 
        g_return_if_fail (object_path != NULL);
562
 
        g_return_if_fail (mediator->priv->object_path == NULL);
563
 
 
564
 
        mediator->priv->object_path = g_strdup (object_path);
565
 
}
566
 
 
567
 
static void
568
 
authentication_mediator_set_sender (EAuthenticationMediator *mediator,
569
 
                                    const gchar *sender)
570
 
{
571
 
        g_return_if_fail (sender != NULL);
572
 
        g_return_if_fail (mediator->priv->sender == NULL);
573
 
 
574
 
        mediator->priv->sender = g_strdup (sender);
575
 
}
576
 
 
577
 
static void
578
 
authentication_mediator_set_property (GObject *object,
579
 
                                      guint property_id,
580
 
                                      const GValue *value,
581
 
                                      GParamSpec *pspec)
582
 
{
583
 
        switch (property_id) {
584
 
                case PROP_CONNECTION:
585
 
                        authentication_mediator_set_connection (
586
 
                                E_AUTHENTICATION_MEDIATOR (object),
587
 
                                g_value_get_object (value));
588
 
                        return;
589
 
 
590
 
                case PROP_OBJECT_PATH:
591
 
                        authentication_mediator_set_object_path (
592
 
                                E_AUTHENTICATION_MEDIATOR (object),
593
 
                                g_value_get_string (value));
594
 
                        return;
595
 
 
596
 
                case PROP_SENDER:
597
 
                        authentication_mediator_set_sender (
598
 
                                E_AUTHENTICATION_MEDIATOR (object),
599
 
                                g_value_get_string (value));
600
 
                        return;
601
 
        }
602
 
 
603
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
604
 
}
605
 
 
606
 
static void
607
 
authentication_mediator_get_property (GObject *object,
608
 
                                      guint property_id,
609
 
                                      GValue *value,
610
 
                                      GParamSpec *pspec)
611
 
{
612
 
        switch (property_id) {
613
 
                case PROP_CONNECTION:
614
 
                        g_value_set_object (
615
 
                                value,
616
 
                                e_authentication_mediator_get_connection (
617
 
                                E_AUTHENTICATION_MEDIATOR (object)));
618
 
                        return;
619
 
 
620
 
                case PROP_OBJECT_PATH:
621
 
                        g_value_set_string (
622
 
                                value,
623
 
                                e_authentication_mediator_get_object_path (
624
 
                                E_AUTHENTICATION_MEDIATOR (object)));
625
 
                        return;
626
 
 
627
 
                case PROP_SENDER:
628
 
                        g_value_set_string (
629
 
                                value,
630
 
                                e_authentication_mediator_get_sender (
631
 
                                E_AUTHENTICATION_MEDIATOR (object)));
632
 
                        return;
633
 
        }
634
 
 
635
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
636
 
}
637
 
 
638
 
static void
639
 
authentication_mediator_dispose (GObject *object)
640
 
{
641
 
        EAuthenticationMediatorPrivate *priv;
642
 
        GQueue *queue;
643
 
 
644
 
        priv = E_AUTHENTICATION_MEDIATOR_GET_PRIVATE (object);
645
 
 
646
 
        /* Signal the authenticator thread to terminate. */
647
 
        if (priv->thread_closure != NULL) {
648
 
                g_main_loop_quit (priv->thread_closure->main_loop);
649
 
                thread_closure_unref (priv->thread_closure);
650
 
                priv->thread_closure = NULL;
651
 
        }
652
 
 
653
 
        if (priv->connection != NULL) {
654
 
                g_object_unref (priv->connection);
655
 
                priv->connection = NULL;
656
 
        }
657
 
 
658
 
        if (priv->dbus_interface != NULL) {
659
 
                g_object_unref (priv->dbus_interface);
660
 
                priv->dbus_interface = NULL;
661
 
        }
662
 
 
663
 
        if (priv->secret_exchange != NULL) {
664
 
                g_object_unref (priv->secret_exchange);
665
 
                priv->secret_exchange = NULL;
666
 
        }
667
 
 
668
 
        queue = &priv->wait_for_client_queue;
669
 
 
670
 
        while (!g_queue_is_empty (queue))
671
 
                g_object_unref (g_queue_pop_head (queue));
672
 
 
673
 
        if (priv->watcher_id > 0) {
674
 
                g_bus_unwatch_name (priv->watcher_id);
675
 
                priv->watcher_id = 0;
676
 
        }
677
 
 
678
 
        /* Chain up to parent's dispose() method. */
679
 
        G_OBJECT_CLASS (e_authentication_mediator_parent_class)->
680
 
                dispose (object);
681
 
}
682
 
 
683
 
static void
684
 
authentication_mediator_finalize (GObject *object)
685
 
{
686
 
        EAuthenticationMediatorPrivate *priv;
687
 
 
688
 
        priv = E_AUTHENTICATION_MEDIATOR_GET_PRIVATE (object);
689
 
 
690
 
        g_mutex_clear (&priv->shared_data_lock);
691
 
 
692
 
        g_free (priv->object_path);
693
 
        g_free (priv->sender);
694
 
 
695
 
        /* Chain up to parent's finalize() method. */
696
 
        G_OBJECT_CLASS (e_authentication_mediator_parent_class)->
697
 
                finalize (object);
698
 
}
699
 
 
700
 
static void
701
 
authentication_mediator_constructed (GObject *object)
702
 
{
703
 
        EAuthenticationMediator *mediator;
704
 
        GDBusConnection *connection;
705
 
        const gchar *sender;
706
 
 
707
 
        mediator = E_AUTHENTICATION_MEDIATOR (object);
708
 
        connection = e_authentication_mediator_get_connection (mediator);
709
 
        sender = e_authentication_mediator_get_sender (mediator);
710
 
 
711
 
        /* This should notify us if the client process terminates. */
712
 
        mediator->priv->watcher_id =
713
 
                g_bus_watch_name_on_connection (
714
 
                        connection, sender,
715
 
                        G_BUS_NAME_WATCHER_FLAGS_NONE,
716
 
                        NULL,
717
 
                        authentication_mediator_name_vanished_cb,
718
 
                        mediator, (GDestroyNotify) NULL);
719
 
 
720
 
        /* Chain up to parent's constructed() method. */
721
 
        G_OBJECT_CLASS (e_authentication_mediator_parent_class)->constructed (object);
722
 
}
723
 
 
724
 
static gboolean
725
 
authentication_mediator_initable_init (GInitable *initable,
726
 
                                       GCancellable *cancellable,
727
 
                                       GError **error)
728
 
{
729
 
        EAuthenticationMediator *mediator;
730
 
        ThreadClosure *closure;
731
 
        GThread *thread;
732
 
 
733
 
        mediator = E_AUTHENTICATION_MEDIATOR (initable);
734
 
 
735
 
        /* The first closure reference is for the authenticator thread. */
736
 
        closure = thread_closure_new (mediator);
737
 
 
738
 
        /* The mediator holds the second closure reference since we need
739
 
         * to tell the authenticator thread's main loop to quit when the
740
 
         * mediator is disposed.  Terminating the authenticator thread's
741
 
         * main loop will signal the thread itself to terminate. */
742
 
        mediator->priv->thread_closure = thread_closure_ref (closure);
743
 
 
744
 
        thread = g_thread_new (
745
 
                NULL,
746
 
                authentication_mediator_authenticator_thread,
747
 
                closure);
748
 
 
749
 
        if (thread == NULL) {
750
 
                thread_closure_unref (closure);
751
 
                return FALSE;
752
 
        }
753
 
 
754
 
        g_thread_unref (thread);
755
 
 
756
 
        /* Wait for notification that the Authenticator interface
757
 
         * has been exported and the thread's main loop started. */
758
 
        g_mutex_lock (&closure->main_loop_mutex);
759
 
        while (!g_main_loop_is_running (closure->main_loop))
760
 
                g_cond_wait (
761
 
                        &closure->main_loop_cond,
762
 
                        &closure->main_loop_mutex);
763
 
        g_mutex_unlock (&closure->main_loop_mutex);
764
 
 
765
 
        /* Check whether the interface failed to export. */
766
 
        if (closure->export_error != NULL) {
767
 
                g_propagate_error (error, closure->export_error);
768
 
                closure->export_error = NULL;
769
 
                return FALSE;
770
 
        }
771
 
 
772
 
        return TRUE;
773
 
}
774
 
 
775
 
static gboolean
776
 
authentication_mediator_get_without_password (ESourceAuthenticator *auth)
777
 
{
778
 
        EAuthenticationMediator *mediator;
779
 
 
780
 
        mediator = E_AUTHENTICATION_MEDIATOR (auth);
781
 
 
782
 
        return e_dbus_authenticator_get_without_password (mediator->priv->dbus_interface);
783
 
}
784
 
 
785
 
static ESourceAuthenticationResult
786
 
authentication_mediator_try_password_sync (ESourceAuthenticator *auth,
787
 
                                           const GString *password,
788
 
                                           GCancellable *cancellable,
789
 
                                           GError **error)
790
 
{
791
 
        ESourceAuthenticationResult auth_result;
792
 
        GAsyncResult *async_result;
793
 
        EAsyncClosure *closure;
794
 
 
795
 
        closure = e_async_closure_new ();
796
 
 
797
 
        e_source_authenticator_try_password (
798
 
                auth, password, cancellable,
799
 
                e_async_closure_callback, closure);
800
 
 
801
 
        async_result = e_async_closure_wait (closure);
802
 
 
803
 
        auth_result = e_source_authenticator_try_password_finish (
804
 
                auth, async_result, error);
805
 
 
806
 
        e_async_closure_free (closure);
807
 
 
808
 
        return auth_result;
809
 
}
810
 
 
811
 
static void
812
 
authentication_mediator_try_password (ESourceAuthenticator *auth,
813
 
                                      const GString *password,
814
 
                                      GCancellable *cancellable,
815
 
                                      GAsyncReadyCallback callback,
816
 
                                      gpointer user_data)
817
 
{
818
 
        EAuthenticationMediator *mediator;
819
 
        GSimpleAsyncResult *simple;
820
 
        AsyncContext *async_context;
821
 
 
822
 
        mediator = E_AUTHENTICATION_MEDIATOR (auth);
823
 
 
824
 
        async_context = g_slice_new0 (AsyncContext);
825
 
        async_context->shared_data_lock = &mediator->priv->shared_data_lock;
826
 
        async_context->operation_queue = &mediator->priv->try_password_queue;
827
 
 
828
 
        simple = g_simple_async_result_new (
829
 
                G_OBJECT (mediator), callback, user_data,
830
 
                authentication_mediator_try_password);
831
 
 
832
 
        g_simple_async_result_set_check_cancellable (simple, cancellable);
833
 
 
834
 
        g_simple_async_result_set_op_res_gpointer (
835
 
                simple, async_context, (GDestroyNotify) async_context_free);
836
 
 
837
 
        if (G_IS_CANCELLABLE (cancellable)) {
838
 
                async_context->cancellable = g_object_ref (cancellable);
839
 
                async_context->cancel_id = g_cancellable_connect (
840
 
                        async_context->cancellable,
841
 
                        G_CALLBACK (authentication_mediator_cancelled_cb),
842
 
                        simple, (GDestroyNotify) NULL);
843
 
        }
844
 
 
845
 
        async_context->timeout_id = e_named_timeout_add_seconds (
846
 
                INACTIVITY_TIMEOUT,
847
 
                authentication_mediator_timeout_cb, simple);
848
 
 
849
 
        g_mutex_lock (&mediator->priv->shared_data_lock);
850
 
 
851
 
        if (mediator->priv->client_cancelled) {
852
 
                g_simple_async_result_set_error (
853
 
                        simple, G_IO_ERROR, G_IO_ERROR_CANCELLED,
854
 
                        "%s", _("Client cancelled the operation"));
855
 
                g_simple_async_result_complete_in_idle (simple);
856
 
 
857
 
        } else if (mediator->priv->client_vanished) {
858
 
                g_simple_async_result_set_error (
859
 
                        simple, G_IO_ERROR, G_IO_ERROR_CANCELLED,
860
 
                        "%s", _("Bus name vanished (client terminated?)"));
861
 
                g_simple_async_result_complete_in_idle (simple);
862
 
 
863
 
        } else {
864
 
                gchar *encrypted_secret;
865
 
 
866
 
                g_queue_push_tail (
867
 
                        async_context->operation_queue,
868
 
                        g_object_ref (simple));
869
 
 
870
 
                encrypted_secret = gcr_secret_exchange_send (
871
 
                        mediator->priv->secret_exchange, password->str, -1);
872
 
 
873
 
                e_dbus_authenticator_emit_authenticate (
874
 
                        mediator->priv->dbus_interface, encrypted_secret);
875
 
 
876
 
                g_free (encrypted_secret);
877
 
        }
878
 
 
879
 
        g_mutex_unlock (&mediator->priv->shared_data_lock);
880
 
 
881
 
        g_object_unref (simple);
882
 
}
883
 
 
884
 
static ESourceAuthenticationResult
885
 
authentication_mediator_try_password_finish (ESourceAuthenticator *auth,
886
 
                                             GAsyncResult *result,
887
 
                                             GError **error)
888
 
{
889
 
        GSimpleAsyncResult *simple;
890
 
        GError *local_error = NULL;
891
 
 
892
 
        simple = G_SIMPLE_ASYNC_RESULT (result);
893
 
 
894
 
        if (!g_simple_async_result_propagate_error (simple, &local_error))
895
 
                return E_SOURCE_AUTHENTICATION_ACCEPTED;
896
 
 
897
 
        if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED)) {
898
 
                g_clear_error (&local_error);
899
 
                return E_SOURCE_AUTHENTICATION_REJECTED;
900
 
        }
901
 
 
902
 
        g_propagate_error (error, local_error);
903
 
 
904
 
        return E_SOURCE_AUTHENTICATION_ERROR;
905
 
}
906
 
 
907
 
static void
908
 
e_authentication_mediator_class_init (EAuthenticationMediatorClass *class)
909
 
{
910
 
        GObjectClass *object_class;
911
 
 
912
 
        g_type_class_add_private (
913
 
                class, sizeof (EAuthenticationMediatorPrivate));
914
 
 
915
 
        object_class = G_OBJECT_CLASS (class);
916
 
        object_class->set_property = authentication_mediator_set_property;
917
 
        object_class->get_property = authentication_mediator_get_property;
918
 
        object_class->dispose = authentication_mediator_dispose;
919
 
        object_class->finalize = authentication_mediator_finalize;
920
 
        object_class->constructed = authentication_mediator_constructed;
921
 
 
922
 
        g_object_class_install_property (
923
 
                object_class,
924
 
                PROP_CONNECTION,
925
 
                g_param_spec_object (
926
 
                        "connection",
927
 
                        "Connection",
928
 
                        "The GDBusConnection on which to "
929
 
                        "export the authenticator interface",
930
 
                        G_TYPE_DBUS_CONNECTION,
931
 
                        G_PARAM_READWRITE |
932
 
                        G_PARAM_CONSTRUCT_ONLY |
933
 
                        G_PARAM_STATIC_STRINGS));
934
 
 
935
 
        g_object_class_install_property (
936
 
                object_class,
937
 
                PROP_OBJECT_PATH,
938
 
                g_param_spec_string (
939
 
                        "object-path",
940
 
                        "Object Path",
941
 
                        "The object path at which to "
942
 
                        "export the authenticator interface",
943
 
                        NULL,
944
 
                        G_PARAM_READWRITE |
945
 
                        G_PARAM_CONSTRUCT_ONLY |
946
 
                        G_PARAM_STATIC_STRINGS));
947
 
 
948
 
        g_object_class_install_property (
949
 
                object_class,
950
 
                PROP_SENDER,
951
 
                g_param_spec_string (
952
 
                        "sender",
953
 
                        "Sender",
954
 
                        "Unique bus name of the process that "
955
 
                        "initiated the authentication session",
956
 
                        NULL,
957
 
                        G_PARAM_READWRITE |
958
 
                        G_PARAM_CONSTRUCT_ONLY |
959
 
                        G_PARAM_STATIC_STRINGS));
960
 
}
961
 
 
962
 
static void
963
 
e_authentication_mediator_initable_init (GInitableIface *iface)
964
 
{
965
 
        iface->init = authentication_mediator_initable_init;
966
 
}
967
 
 
968
 
static void
969
 
e_authentication_mediator_interface_init (ESourceAuthenticatorInterface *iface)
970
 
{
971
 
        iface->get_without_password =
972
 
                authentication_mediator_get_without_password;
973
 
        iface->try_password_sync =
974
 
                authentication_mediator_try_password_sync;
975
 
        iface->try_password =
976
 
                authentication_mediator_try_password;
977
 
        iface->try_password_finish =
978
 
                authentication_mediator_try_password_finish;
979
 
}
980
 
 
981
 
static void
982
 
e_authentication_mediator_init (EAuthenticationMediator *mediator)
983
 
{
984
 
        mediator->priv = E_AUTHENTICATION_MEDIATOR_GET_PRIVATE (mediator);
985
 
 
986
 
        mediator->priv->dbus_interface = e_dbus_authenticator_skeleton_new ();
987
 
        mediator->priv->secret_exchange = gcr_secret_exchange_new (NULL);
988
 
 
989
 
        g_mutex_init (&mediator->priv->shared_data_lock);
990
 
}
991
 
 
992
 
/**
993
 
 * e_authentication_mediator_new:
994
 
 * @connection: a #GDBusConnection
995
 
 * @object_path: object path of the authentication session
996
 
 * @sender: bus name of the client requesting authentication
997
 
 * @error: return location for a #GError, or %NULL
998
 
 *
999
 
 * Creates a new #EAuthenticationMediator and exports the Authenticator
1000
 
 * D-Bus interface on @connection at @object_path.  If the Authenticator
1001
 
 * interface fails to export, the function sets @error and returns %NULL.
1002
 
 *
1003
 
 * #EAuthenticationMediator watches the bus name of the client requesting
1004
 
 * authentication, given by @sender.  If it sees the bus name vanish, it
1005
 
 * cancels the authentication session so the next authentication session
1006
 
 * can begin without delay.
1007
 
 *
1008
 
 * Returns: an #EAuthenticationMediator, or %NULL on error
1009
 
 *
1010
 
 * Since: 3.6
1011
 
 **/
1012
 
ESourceAuthenticator *
1013
 
e_authentication_mediator_new (GDBusConnection *connection,
1014
 
                               const gchar *object_path,
1015
 
                               const gchar *sender,
1016
 
                               GError **error)
1017
 
{
1018
 
        g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
1019
 
        g_return_val_if_fail (object_path != NULL, NULL);
1020
 
        g_return_val_if_fail (sender != NULL, NULL);
1021
 
 
1022
 
        return g_initable_new (
1023
 
                E_TYPE_AUTHENTICATION_MEDIATOR, NULL, error,
1024
 
                "connection", connection,
1025
 
                "object-path", object_path,
1026
 
                "sender", sender, NULL);
1027
 
}
1028
 
 
1029
 
/**
1030
 
 * e_authentication_mediator_get_connection:
1031
 
 * @mediator: an #EAuthenticationMediator
1032
 
 *
1033
 
 * Returns the #GDBusConnection on which the Authenticator D-Bus interface
1034
 
 * is exported.
1035
 
 *
1036
 
 * Returns: the #GDBusConnection
1037
 
 *
1038
 
 * Since: 3.6
1039
 
 **/
1040
 
GDBusConnection *
1041
 
e_authentication_mediator_get_connection (EAuthenticationMediator *mediator)
1042
 
{
1043
 
        g_return_val_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator), NULL);
1044
 
 
1045
 
        return mediator->priv->connection;
1046
 
}
1047
 
 
1048
 
/**
1049
 
 * e_authentication_mediator_get_object_path:
1050
 
 * @mediator: an #EAuthenticationMediator
1051
 
 *
1052
 
 * Returns the object path at which the Authenticator D-Bus interface is
1053
 
 * exported.
1054
 
 *
1055
 
 * Returns: the object path
1056
 
 *
1057
 
 * Since: 3.6
1058
 
 **/
1059
 
const gchar *
1060
 
e_authentication_mediator_get_object_path (EAuthenticationMediator *mediator)
1061
 
{
1062
 
        g_return_val_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator), NULL);
1063
 
 
1064
 
        return mediator->priv->object_path;
1065
 
}
1066
 
 
1067
 
/**
1068
 
 * e_authentication_mediator_get_sender:
1069
 
 * @mediator: an #EAuthenticationMediator
1070
 
 *
1071
 
 * Returns the authentication client's unique bus name.
1072
 
 *
1073
 
 * Returns: the client's bus name
1074
 
 *
1075
 
 * Since: 3.6
1076
 
 **/
1077
 
const gchar *
1078
 
e_authentication_mediator_get_sender (EAuthenticationMediator *mediator)
1079
 
{
1080
 
        g_return_val_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator), NULL);
1081
 
 
1082
 
        return mediator->priv->sender;
1083
 
}
1084
 
 
1085
 
/**
1086
 
 * e_authentication_mediator_wait_for_client_sync:
1087
 
 * @mediator: an #EAuthenticationMediator
1088
 
 * @cancellable: optional #GCancellable object, or %NULL
1089
 
 * @error: return location for a #GError, or %NULL
1090
 
 *
1091
 
 * Waits for the authentication client to indicate it is ready to begin
1092
 
 * authentication attempts.  Call this function to synchronize with the
1093
 
 * client before initiating any authentication attempts through @mediator.
1094
 
 *
1095
 
 * If the authentication client's bus name vanishes or the client fails
1096
 
 * to signal it is ready before a timer expires, the function sets @error
1097
 
 * and returns %FALSE.
1098
 
 *
1099
 
 * Returns: %TRUE if the client is ready, %FALSE if an error occurred
1100
 
 *
1101
 
 * Since: 3.6
1102
 
 **/
1103
 
gboolean
1104
 
e_authentication_mediator_wait_for_client_sync (EAuthenticationMediator *mediator,
1105
 
                                                GCancellable *cancellable,
1106
 
                                                GError **error)
1107
 
{
1108
 
        EAsyncClosure *closure;
1109
 
        GAsyncResult *result;
1110
 
        gboolean success;
1111
 
 
1112
 
        g_return_val_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator), FALSE);
1113
 
 
1114
 
        closure = e_async_closure_new ();
1115
 
 
1116
 
        e_authentication_mediator_wait_for_client (
1117
 
                mediator, cancellable, e_async_closure_callback, closure);
1118
 
 
1119
 
        result = e_async_closure_wait (closure);
1120
 
 
1121
 
        success = e_authentication_mediator_wait_for_client_finish (
1122
 
                mediator, result, error);
1123
 
 
1124
 
        e_async_closure_free (closure);
1125
 
 
1126
 
        return success;
1127
 
}
1128
 
 
1129
 
/**
1130
 
 * e_authentication_mediator_wait_for_client:
1131
 
 * @mediator: an #EAuthenticationMediator
1132
 
 * @cancellable: optional #GCancellable object, or %NULL
1133
 
 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1134
 
 * @user_data: data to pass to the callback function
1135
 
 *
1136
 
 * Asynchronously waits for the authentication client to indicate it
1137
 
 * is ready to being authentication attempts.  Call this function to
1138
 
 * synchronize with the client before initiating any authentication
1139
 
 * attempts through @mediator.
1140
 
 *
1141
 
 * When the operation is finished, @callback will be called.  You can then
1142
 
 * call e_authentication_mediator_wait_for_client_finished() to get the
1143
 
 * result of the operation.
1144
 
 *
1145
 
 * Since: 3.6
1146
 
 **/
1147
 
void
1148
 
e_authentication_mediator_wait_for_client (EAuthenticationMediator *mediator,
1149
 
                                           GCancellable *cancellable,
1150
 
                                           GAsyncReadyCallback callback,
1151
 
                                           gpointer user_data)
1152
 
{
1153
 
        GSimpleAsyncResult *simple;
1154
 
        AsyncContext *async_context;
1155
 
 
1156
 
        g_return_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator));
1157
 
 
1158
 
        async_context = g_slice_new0 (AsyncContext);
1159
 
        async_context->shared_data_lock = &mediator->priv->shared_data_lock;
1160
 
        async_context->operation_queue = &mediator->priv->wait_for_client_queue;
1161
 
 
1162
 
        simple = g_simple_async_result_new (
1163
 
                G_OBJECT (mediator), callback, user_data,
1164
 
                e_authentication_mediator_wait_for_client);
1165
 
 
1166
 
        g_simple_async_result_set_check_cancellable (simple, cancellable);
1167
 
 
1168
 
        g_simple_async_result_set_op_res_gpointer (
1169
 
                simple, async_context, (GDestroyNotify) async_context_free);
1170
 
 
1171
 
        if (G_IS_CANCELLABLE (cancellable)) {
1172
 
                async_context->cancellable = g_object_ref (cancellable);
1173
 
                async_context->cancel_id = g_cancellable_connect (
1174
 
                        cancellable,
1175
 
                        G_CALLBACK (authentication_mediator_cancelled_cb),
1176
 
                        simple, (GDestroyNotify) NULL);
1177
 
        }
1178
 
 
1179
 
        async_context->timeout_id = e_named_timeout_add_seconds (
1180
 
                INACTIVITY_TIMEOUT,
1181
 
                authentication_mediator_timeout_cb, simple);
1182
 
 
1183
 
        g_mutex_lock (&mediator->priv->shared_data_lock);
1184
 
 
1185
 
        if (mediator->priv->client_is_ready) {
1186
 
                g_simple_async_result_complete_in_idle (simple);
1187
 
 
1188
 
        } else if (mediator->priv->client_cancelled) {
1189
 
                g_simple_async_result_set_error (
1190
 
                        simple, G_IO_ERROR, G_IO_ERROR_CANCELLED,
1191
 
                        "%s", _("Client cancelled the operation"));
1192
 
                g_simple_async_result_complete_in_idle (simple);
1193
 
 
1194
 
        } else if (mediator->priv->client_vanished) {
1195
 
                g_simple_async_result_set_error (
1196
 
                        simple, G_IO_ERROR, G_IO_ERROR_CANCELLED,
1197
 
                        "%s", _("Bus name vanished (client terminated?)"));
1198
 
                g_simple_async_result_complete_in_idle (simple);
1199
 
 
1200
 
        } else {
1201
 
                g_queue_push_tail (
1202
 
                        async_context->operation_queue,
1203
 
                        g_object_ref (simple));
1204
 
        }
1205
 
 
1206
 
        g_mutex_unlock (&mediator->priv->shared_data_lock);
1207
 
 
1208
 
        g_object_unref (simple);
1209
 
}
1210
 
 
1211
 
/**
1212
 
 * e_authentication_mediator_wait_for_client_finish:
1213
 
 * @mediator: an #EAuthenticationMediator
1214
 
 * @result: a #GAsyncResult
1215
 
 * @error: return location for a #GError, or %NULL
1216
 
 *
1217
 
 * Finishes the operation started with
1218
 
 * e_authentication_mediator_wait_for_client().
1219
 
 *
1220
 
 * If the authentication client's bus name vanishes or the client fails
1221
 
 * to signal it is ready before a timer expires, the function sets @error
1222
 
 * and returns %FALSE.
1223
 
 *
1224
 
 * Returns: %TRUE if the client is ready, %FALSE if an error occurred
1225
 
 *
1226
 
 * Since: 3.6
1227
 
 **/
1228
 
gboolean
1229
 
e_authentication_mediator_wait_for_client_finish (EAuthenticationMediator *mediator,
1230
 
                                                  GAsyncResult *result,
1231
 
                                                  GError **error)
1232
 
{
1233
 
        GSimpleAsyncResult *simple;
1234
 
 
1235
 
        g_return_val_if_fail (
1236
 
                g_simple_async_result_is_valid (
1237
 
                result, G_OBJECT (mediator),
1238
 
                e_authentication_mediator_wait_for_client), FALSE);
1239
 
 
1240
 
        simple = G_SIMPLE_ASYNC_RESULT (result);
1241
 
 
1242
 
        /* Assume success unless a GError is set. */
1243
 
        return !g_simple_async_result_propagate_error (simple, error);
1244
 
}
1245
 
 
1246
 
/**
1247
 
 * e_authentication_mediator_dismiss:
1248
 
 * @mediator: an #EAuthenticationMediator
1249
 
 *
1250
 
 * Signals to the authentication client that the user declined to provide a
1251
 
 * password when prompted and that the authentication session has terminated.
1252
 
 * This is also called when a server-side error has occurred, but the client
1253
 
 * doesn't need to know the difference.
1254
 
 *
1255
 
 * Since: 3.6
1256
 
 **/
1257
 
void
1258
 
e_authentication_mediator_dismiss (EAuthenticationMediator *mediator)
1259
 
{
1260
 
        g_return_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator));
1261
 
 
1262
 
        e_dbus_authenticator_emit_dismissed (mediator->priv->dbus_interface);
1263
 
}
1264
 
 
1265
 
/**
1266
 
 * e_authentication_mediator_server_error:
1267
 
 * @mediator: an #EAuthenticationMediator
1268
 
 * @error: the #GError to report
1269
 
 *
1270
 
 * Signals to the authentication client that the authentication session has
1271
 
 * terminated with a server-side error.
1272
 
 *
1273
 
 * Since: 3.12
1274
 
 **/
1275
 
void
1276
 
e_authentication_mediator_server_error (EAuthenticationMediator *mediator,
1277
 
                                        const GError *error)
1278
 
{
1279
 
        gchar *name;
1280
 
 
1281
 
        g_return_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator));
1282
 
        g_return_if_fail (error != NULL);
1283
 
 
1284
 
        name = g_dbus_error_encode_gerror (error);
1285
 
        g_return_if_fail (name != NULL);
1286
 
 
1287
 
        e_dbus_authenticator_emit_server_error (mediator->priv->dbus_interface, name, error->message);
1288
 
 
1289
 
        g_free (name);
1290
 
}