2
* e-authentication-mediator.c
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.
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
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/>.
19
* SECTION: e-authentication-mediator
20
* @include: libebackend/libebackend.h
21
* @short_description: Authenticator proxy for remote clients
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.
30
#include "e-authentication-mediator.h"
32
/* XXX Yeah, yeah... */
33
#define GCR_API_SUBJECT_TO_CHANGE
36
#include <glib/gi18n-lib.h>
37
#include <gcr/gcr-base.h>
39
/* Private D-Bus classes. */
40
#include <e-dbus-authenticator.h>
42
#define E_AUTHENTICATION_MEDIATOR_GET_PRIVATE(obj) \
43
(G_TYPE_INSTANCE_GET_PRIVATE \
44
((obj), E_TYPE_AUTHENTICATION_MEDIATOR, EAuthenticationMediatorPrivate))
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 */
51
typedef struct _AsyncContext AsyncContext;
52
typedef struct _ThreadClosure ThreadClosure;
54
struct _EAuthenticationMediatorPrivate {
55
GDBusConnection *connection;
56
EDBusAuthenticator *dbus_interface;
57
GcrSecretExchange *secret_exchange;
61
ThreadClosure *thread_closure;
63
GMutex shared_data_lock;
65
GQueue try_password_queue;
66
GQueue wait_for_client_queue;
68
gboolean client_is_ready;
69
gboolean client_cancelled;
70
gboolean client_vanished;
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;
81
GCancellable *cancellable;
86
struct _ThreadClosure {
87
volatile gint ref_count;
89
GMainContext *main_context;
92
GMutex main_loop_mutex;
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);
109
G_DEFINE_TYPE_WITH_CODE (
110
EAuthenticationMediator,
111
e_authentication_mediator,
113
G_IMPLEMENT_INTERFACE (
115
e_authentication_mediator_initable_init)
116
G_IMPLEMENT_INTERFACE (
117
E_TYPE_SOURCE_AUTHENTICATOR,
118
e_authentication_mediator_interface_init))
121
async_context_free (AsyncContext *async_context)
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);
130
if (async_context->timeout_id > 0)
131
g_source_remove (async_context->timeout_id);
133
g_slice_free (AsyncContext, async_context);
136
static ThreadClosure *
137
thread_closure_new (EAuthenticationMediator *mediator)
139
ThreadClosure *closure;
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);
155
static ThreadClosure *
156
thread_closure_ref (ThreadClosure *closure)
158
g_return_val_if_fail (closure != NULL, NULL);
159
g_return_val_if_fail (closure->ref_count > 0, NULL);
161
g_atomic_int_inc (&closure->ref_count);
167
thread_closure_unref (ThreadClosure *closure)
169
g_return_if_fail (closure != NULL);
170
g_return_if_fail (closure->ref_count > 0);
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);
179
g_slice_free (ThreadClosure, closure);
184
authentication_mediator_name_vanished_cb (GDBusConnection *connection,
188
EAuthenticationMediator *mediator;
189
GSimpleAsyncResult *simple;
192
mediator = E_AUTHENTICATION_MEDIATOR (user_data);
194
g_mutex_lock (&mediator->priv->shared_data_lock);
196
mediator->priv->client_vanished = TRUE;
198
queue = &mediator->priv->try_password_queue;
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);
209
queue = &mediator->priv->wait_for_client_queue;
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);
220
g_bus_unwatch_name (mediator->priv->watcher_id);
221
mediator->priv->watcher_id = 0;
223
g_mutex_unlock (&mediator->priv->shared_data_lock);
227
authentication_mediator_cancelled_cb (GCancellable *cancellable,
230
GSimpleAsyncResult *simple;
231
AsyncContext *async_context;
233
simple = G_SIMPLE_ASYNC_RESULT (user_data);
234
async_context = g_simple_async_result_get_op_res_gpointer (simple);
236
g_mutex_lock (async_context->shared_data_lock);
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);
246
g_mutex_unlock (async_context->shared_data_lock);
250
authentication_mediator_timeout_cb (gpointer user_data)
252
GSimpleAsyncResult *simple;
253
AsyncContext *async_context;
255
simple = G_SIMPLE_ASYNC_RESULT (user_data);
256
async_context = g_simple_async_result_get_op_res_gpointer (simple);
258
g_mutex_lock (async_context->shared_data_lock);
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);
268
g_mutex_unlock (async_context->shared_data_lock);
274
authentication_mediator_handle_ready (EDBusAuthenticator *dbus_interface,
275
GDBusMethodInvocation *invocation,
276
const gchar *encrypted_key,
277
ThreadClosure *closure)
279
EAuthenticationMediator *mediator;
280
GcrSecretExchange *secret_exchange;
281
GSimpleAsyncResult *simple;
284
mediator = g_weak_ref_get (&closure->mediator);
285
g_return_val_if_fail (mediator != NULL, FALSE);
287
g_mutex_lock (&mediator->priv->shared_data_lock);
289
mediator->priv->client_is_ready = TRUE;
291
secret_exchange = mediator->priv->secret_exchange;
292
gcr_secret_exchange_receive (secret_exchange, encrypted_key);
294
queue = &mediator->priv->wait_for_client_queue;
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);
302
g_mutex_unlock (&mediator->priv->shared_data_lock);
304
e_dbus_authenticator_complete_ready (dbus_interface, invocation);
306
g_object_unref (mediator);
312
authentication_mediator_handle_cancel (EDBusAuthenticator *dbus_interface,
313
GDBusMethodInvocation *invocation,
314
ThreadClosure *closure)
316
EAuthenticationMediator *mediator;
317
GSimpleAsyncResult *simple;
320
mediator = g_weak_ref_get (&closure->mediator);
321
g_return_val_if_fail (mediator != NULL, FALSE);
323
g_mutex_lock (&mediator->priv->shared_data_lock);
325
mediator->priv->client_cancelled = TRUE;
327
queue = &mediator->priv->try_password_queue;
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);
338
queue = &mediator->priv->wait_for_client_queue;
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);
349
g_mutex_unlock (&mediator->priv->shared_data_lock);
351
e_dbus_authenticator_complete_cancel (dbus_interface, invocation);
353
g_object_unref (mediator);
359
authentication_mediator_handle_accepted (EDBusAuthenticator *dbus_interface,
360
GDBusMethodInvocation *invocation,
361
ThreadClosure *closure)
363
EAuthenticationMediator *mediator;
364
GSimpleAsyncResult *simple;
367
mediator = g_weak_ref_get (&closure->mediator);
368
g_return_val_if_fail (mediator != NULL, FALSE);
370
g_mutex_lock (&mediator->priv->shared_data_lock);
372
queue = &mediator->priv->try_password_queue;
374
if (g_queue_is_empty (queue))
375
g_warning ("%s: Unexpected 'accepted' signal", G_STRFUNC);
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);
383
g_mutex_unlock (&mediator->priv->shared_data_lock);
385
e_dbus_authenticator_complete_accepted (dbus_interface, invocation);
387
g_object_unref (mediator);
393
authentication_mediator_handle_rejected (EDBusAuthenticator *dbus_interface,
394
GDBusMethodInvocation *invocation,
395
ThreadClosure *closure)
397
EAuthenticationMediator *mediator;
398
GSimpleAsyncResult *simple;
401
mediator = g_weak_ref_get (&closure->mediator);
402
g_return_val_if_fail (mediator != NULL, FALSE);
404
g_mutex_lock (&mediator->priv->shared_data_lock);
406
queue = &mediator->priv->try_password_queue;
408
if (g_queue_is_empty (queue))
409
g_warning ("%s: Unexpected 'rejected' signal", G_STRFUNC);
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);
420
g_mutex_unlock (&mediator->priv->shared_data_lock);
422
e_dbus_authenticator_complete_rejected (dbus_interface, invocation);
424
g_object_unref (mediator);
430
authentication_mediator_authenticator_running (gpointer data)
432
ThreadClosure *closure = data;
434
g_mutex_lock (&closure->main_loop_mutex);
435
g_cond_broadcast (&closure->main_loop_cond);
436
g_mutex_unlock (&closure->main_loop_mutex);
442
authentication_mediator_authenticator_thread (gpointer data)
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;
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
463
mediator = g_weak_ref_get (&closure->mediator);
464
g_return_val_if_fail (mediator != NULL, NULL);
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);
470
connection = e_authentication_mediator_get_connection (mediator);
471
object_path = e_authentication_mediator_get_object_path (mediator);
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
478
g_main_context_push_thread_default (closure->main_context);
480
/* Listen for method invocations. */
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);
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);
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);
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);
506
/* Export the Authenticator interface. */
508
g_dbus_interface_skeleton_export (
509
dbus_interface, connection, object_path, &closure->export_error);
511
/* Schedule a one-time idle callback to broadcast through a
512
* condition variable that our main loop is up and running. */
514
idle_source = g_idle_source_new ();
515
g_source_set_callback (
517
authentication_mediator_authenticator_running,
518
closure, (GDestroyNotify) NULL);
519
g_source_attach (idle_source, closure->main_context);
520
g_source_unref (idle_source);
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);
527
/* Now we mostly idle here until authentication is complete. */
529
g_main_loop_run (closure->main_loop);
531
/* Clean up and exit. */
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);
538
g_main_context_pop_thread_default (closure->main_context);
540
g_object_unref (dbus_interface);
542
thread_closure_unref (closure);
548
authentication_mediator_set_connection (EAuthenticationMediator *mediator,
549
GDBusConnection *connection)
551
g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
552
g_return_if_fail (mediator->priv->connection == NULL);
554
mediator->priv->connection = g_object_ref (connection);
558
authentication_mediator_set_object_path (EAuthenticationMediator *mediator,
559
const gchar *object_path)
561
g_return_if_fail (object_path != NULL);
562
g_return_if_fail (mediator->priv->object_path == NULL);
564
mediator->priv->object_path = g_strdup (object_path);
568
authentication_mediator_set_sender (EAuthenticationMediator *mediator,
571
g_return_if_fail (sender != NULL);
572
g_return_if_fail (mediator->priv->sender == NULL);
574
mediator->priv->sender = g_strdup (sender);
578
authentication_mediator_set_property (GObject *object,
583
switch (property_id) {
584
case PROP_CONNECTION:
585
authentication_mediator_set_connection (
586
E_AUTHENTICATION_MEDIATOR (object),
587
g_value_get_object (value));
590
case PROP_OBJECT_PATH:
591
authentication_mediator_set_object_path (
592
E_AUTHENTICATION_MEDIATOR (object),
593
g_value_get_string (value));
597
authentication_mediator_set_sender (
598
E_AUTHENTICATION_MEDIATOR (object),
599
g_value_get_string (value));
603
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
607
authentication_mediator_get_property (GObject *object,
612
switch (property_id) {
613
case PROP_CONNECTION:
616
e_authentication_mediator_get_connection (
617
E_AUTHENTICATION_MEDIATOR (object)));
620
case PROP_OBJECT_PATH:
623
e_authentication_mediator_get_object_path (
624
E_AUTHENTICATION_MEDIATOR (object)));
630
e_authentication_mediator_get_sender (
631
E_AUTHENTICATION_MEDIATOR (object)));
635
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
639
authentication_mediator_dispose (GObject *object)
641
EAuthenticationMediatorPrivate *priv;
644
priv = E_AUTHENTICATION_MEDIATOR_GET_PRIVATE (object);
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;
653
if (priv->connection != NULL) {
654
g_object_unref (priv->connection);
655
priv->connection = NULL;
658
if (priv->dbus_interface != NULL) {
659
g_object_unref (priv->dbus_interface);
660
priv->dbus_interface = NULL;
663
if (priv->secret_exchange != NULL) {
664
g_object_unref (priv->secret_exchange);
665
priv->secret_exchange = NULL;
668
queue = &priv->wait_for_client_queue;
670
while (!g_queue_is_empty (queue))
671
g_object_unref (g_queue_pop_head (queue));
673
if (priv->watcher_id > 0) {
674
g_bus_unwatch_name (priv->watcher_id);
675
priv->watcher_id = 0;
678
/* Chain up to parent's dispose() method. */
679
G_OBJECT_CLASS (e_authentication_mediator_parent_class)->
684
authentication_mediator_finalize (GObject *object)
686
EAuthenticationMediatorPrivate *priv;
688
priv = E_AUTHENTICATION_MEDIATOR_GET_PRIVATE (object);
690
g_mutex_clear (&priv->shared_data_lock);
692
g_free (priv->object_path);
693
g_free (priv->sender);
695
/* Chain up to parent's finalize() method. */
696
G_OBJECT_CLASS (e_authentication_mediator_parent_class)->
701
authentication_mediator_constructed (GObject *object)
703
EAuthenticationMediator *mediator;
704
GDBusConnection *connection;
707
mediator = E_AUTHENTICATION_MEDIATOR (object);
708
connection = e_authentication_mediator_get_connection (mediator);
709
sender = e_authentication_mediator_get_sender (mediator);
711
/* This should notify us if the client process terminates. */
712
mediator->priv->watcher_id =
713
g_bus_watch_name_on_connection (
715
G_BUS_NAME_WATCHER_FLAGS_NONE,
717
authentication_mediator_name_vanished_cb,
718
mediator, (GDestroyNotify) NULL);
720
/* Chain up to parent's constructed() method. */
721
G_OBJECT_CLASS (e_authentication_mediator_parent_class)->constructed (object);
725
authentication_mediator_initable_init (GInitable *initable,
726
GCancellable *cancellable,
729
EAuthenticationMediator *mediator;
730
ThreadClosure *closure;
733
mediator = E_AUTHENTICATION_MEDIATOR (initable);
735
/* The first closure reference is for the authenticator thread. */
736
closure = thread_closure_new (mediator);
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);
744
thread = g_thread_new (
746
authentication_mediator_authenticator_thread,
749
if (thread == NULL) {
750
thread_closure_unref (closure);
754
g_thread_unref (thread);
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))
761
&closure->main_loop_cond,
762
&closure->main_loop_mutex);
763
g_mutex_unlock (&closure->main_loop_mutex);
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;
776
authentication_mediator_get_without_password (ESourceAuthenticator *auth)
778
EAuthenticationMediator *mediator;
780
mediator = E_AUTHENTICATION_MEDIATOR (auth);
782
return e_dbus_authenticator_get_without_password (mediator->priv->dbus_interface);
785
static ESourceAuthenticationResult
786
authentication_mediator_try_password_sync (ESourceAuthenticator *auth,
787
const GString *password,
788
GCancellable *cancellable,
791
ESourceAuthenticationResult auth_result;
792
GAsyncResult *async_result;
793
EAsyncClosure *closure;
795
closure = e_async_closure_new ();
797
e_source_authenticator_try_password (
798
auth, password, cancellable,
799
e_async_closure_callback, closure);
801
async_result = e_async_closure_wait (closure);
803
auth_result = e_source_authenticator_try_password_finish (
804
auth, async_result, error);
806
e_async_closure_free (closure);
812
authentication_mediator_try_password (ESourceAuthenticator *auth,
813
const GString *password,
814
GCancellable *cancellable,
815
GAsyncReadyCallback callback,
818
EAuthenticationMediator *mediator;
819
GSimpleAsyncResult *simple;
820
AsyncContext *async_context;
822
mediator = E_AUTHENTICATION_MEDIATOR (auth);
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;
828
simple = g_simple_async_result_new (
829
G_OBJECT (mediator), callback, user_data,
830
authentication_mediator_try_password);
832
g_simple_async_result_set_check_cancellable (simple, cancellable);
834
g_simple_async_result_set_op_res_gpointer (
835
simple, async_context, (GDestroyNotify) async_context_free);
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);
845
async_context->timeout_id = e_named_timeout_add_seconds (
847
authentication_mediator_timeout_cb, simple);
849
g_mutex_lock (&mediator->priv->shared_data_lock);
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);
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);
864
gchar *encrypted_secret;
867
async_context->operation_queue,
868
g_object_ref (simple));
870
encrypted_secret = gcr_secret_exchange_send (
871
mediator->priv->secret_exchange, password->str, -1);
873
e_dbus_authenticator_emit_authenticate (
874
mediator->priv->dbus_interface, encrypted_secret);
876
g_free (encrypted_secret);
879
g_mutex_unlock (&mediator->priv->shared_data_lock);
881
g_object_unref (simple);
884
static ESourceAuthenticationResult
885
authentication_mediator_try_password_finish (ESourceAuthenticator *auth,
886
GAsyncResult *result,
889
GSimpleAsyncResult *simple;
890
GError *local_error = NULL;
892
simple = G_SIMPLE_ASYNC_RESULT (result);
894
if (!g_simple_async_result_propagate_error (simple, &local_error))
895
return E_SOURCE_AUTHENTICATION_ACCEPTED;
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;
902
g_propagate_error (error, local_error);
904
return E_SOURCE_AUTHENTICATION_ERROR;
908
e_authentication_mediator_class_init (EAuthenticationMediatorClass *class)
910
GObjectClass *object_class;
912
g_type_class_add_private (
913
class, sizeof (EAuthenticationMediatorPrivate));
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;
922
g_object_class_install_property (
925
g_param_spec_object (
928
"The GDBusConnection on which to "
929
"export the authenticator interface",
930
G_TYPE_DBUS_CONNECTION,
932
G_PARAM_CONSTRUCT_ONLY |
933
G_PARAM_STATIC_STRINGS));
935
g_object_class_install_property (
938
g_param_spec_string (
941
"The object path at which to "
942
"export the authenticator interface",
945
G_PARAM_CONSTRUCT_ONLY |
946
G_PARAM_STATIC_STRINGS));
948
g_object_class_install_property (
951
g_param_spec_string (
954
"Unique bus name of the process that "
955
"initiated the authentication session",
958
G_PARAM_CONSTRUCT_ONLY |
959
G_PARAM_STATIC_STRINGS));
963
e_authentication_mediator_initable_init (GInitableIface *iface)
965
iface->init = authentication_mediator_initable_init;
969
e_authentication_mediator_interface_init (ESourceAuthenticatorInterface *iface)
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;
982
e_authentication_mediator_init (EAuthenticationMediator *mediator)
984
mediator->priv = E_AUTHENTICATION_MEDIATOR_GET_PRIVATE (mediator);
986
mediator->priv->dbus_interface = e_dbus_authenticator_skeleton_new ();
987
mediator->priv->secret_exchange = gcr_secret_exchange_new (NULL);
989
g_mutex_init (&mediator->priv->shared_data_lock);
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
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.
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.
1008
* Returns: an #EAuthenticationMediator, or %NULL on error
1012
ESourceAuthenticator *
1013
e_authentication_mediator_new (GDBusConnection *connection,
1014
const gchar *object_path,
1015
const gchar *sender,
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);
1022
return g_initable_new (
1023
E_TYPE_AUTHENTICATION_MEDIATOR, NULL, error,
1024
"connection", connection,
1025
"object-path", object_path,
1026
"sender", sender, NULL);
1030
* e_authentication_mediator_get_connection:
1031
* @mediator: an #EAuthenticationMediator
1033
* Returns the #GDBusConnection on which the Authenticator D-Bus interface
1036
* Returns: the #GDBusConnection
1041
e_authentication_mediator_get_connection (EAuthenticationMediator *mediator)
1043
g_return_val_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator), NULL);
1045
return mediator->priv->connection;
1049
* e_authentication_mediator_get_object_path:
1050
* @mediator: an #EAuthenticationMediator
1052
* Returns the object path at which the Authenticator D-Bus interface is
1055
* Returns: the object path
1060
e_authentication_mediator_get_object_path (EAuthenticationMediator *mediator)
1062
g_return_val_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator), NULL);
1064
return mediator->priv->object_path;
1068
* e_authentication_mediator_get_sender:
1069
* @mediator: an #EAuthenticationMediator
1071
* Returns the authentication client's unique bus name.
1073
* Returns: the client's bus name
1078
e_authentication_mediator_get_sender (EAuthenticationMediator *mediator)
1080
g_return_val_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator), NULL);
1082
return mediator->priv->sender;
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
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.
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.
1099
* Returns: %TRUE if the client is ready, %FALSE if an error occurred
1104
e_authentication_mediator_wait_for_client_sync (EAuthenticationMediator *mediator,
1105
GCancellable *cancellable,
1108
EAsyncClosure *closure;
1109
GAsyncResult *result;
1112
g_return_val_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator), FALSE);
1114
closure = e_async_closure_new ();
1116
e_authentication_mediator_wait_for_client (
1117
mediator, cancellable, e_async_closure_callback, closure);
1119
result = e_async_closure_wait (closure);
1121
success = e_authentication_mediator_wait_for_client_finish (
1122
mediator, result, error);
1124
e_async_closure_free (closure);
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
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.
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.
1148
e_authentication_mediator_wait_for_client (EAuthenticationMediator *mediator,
1149
GCancellable *cancellable,
1150
GAsyncReadyCallback callback,
1153
GSimpleAsyncResult *simple;
1154
AsyncContext *async_context;
1156
g_return_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator));
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;
1162
simple = g_simple_async_result_new (
1163
G_OBJECT (mediator), callback, user_data,
1164
e_authentication_mediator_wait_for_client);
1166
g_simple_async_result_set_check_cancellable (simple, cancellable);
1168
g_simple_async_result_set_op_res_gpointer (
1169
simple, async_context, (GDestroyNotify) async_context_free);
1171
if (G_IS_CANCELLABLE (cancellable)) {
1172
async_context->cancellable = g_object_ref (cancellable);
1173
async_context->cancel_id = g_cancellable_connect (
1175
G_CALLBACK (authentication_mediator_cancelled_cb),
1176
simple, (GDestroyNotify) NULL);
1179
async_context->timeout_id = e_named_timeout_add_seconds (
1181
authentication_mediator_timeout_cb, simple);
1183
g_mutex_lock (&mediator->priv->shared_data_lock);
1185
if (mediator->priv->client_is_ready) {
1186
g_simple_async_result_complete_in_idle (simple);
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);
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);
1202
async_context->operation_queue,
1203
g_object_ref (simple));
1206
g_mutex_unlock (&mediator->priv->shared_data_lock);
1208
g_object_unref (simple);
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
1217
* Finishes the operation started with
1218
* e_authentication_mediator_wait_for_client().
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.
1224
* Returns: %TRUE if the client is ready, %FALSE if an error occurred
1229
e_authentication_mediator_wait_for_client_finish (EAuthenticationMediator *mediator,
1230
GAsyncResult *result,
1233
GSimpleAsyncResult *simple;
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);
1240
simple = G_SIMPLE_ASYNC_RESULT (result);
1242
/* Assume success unless a GError is set. */
1243
return !g_simple_async_result_propagate_error (simple, error);
1247
* e_authentication_mediator_dismiss:
1248
* @mediator: an #EAuthenticationMediator
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.
1258
e_authentication_mediator_dismiss (EAuthenticationMediator *mediator)
1260
g_return_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator));
1262
e_dbus_authenticator_emit_dismissed (mediator->priv->dbus_interface);
1266
* e_authentication_mediator_server_error:
1267
* @mediator: an #EAuthenticationMediator
1268
* @error: the #GError to report
1270
* Signals to the authentication client that the authentication session has
1271
* terminated with a server-side error.
1276
e_authentication_mediator_server_error (EAuthenticationMediator *mediator,
1277
const GError *error)
1281
g_return_if_fail (E_IS_AUTHENTICATION_MEDIATOR (mediator));
1282
g_return_if_fail (error != NULL);
1284
name = g_dbus_error_encode_gerror (error);
1285
g_return_if_fail (name != NULL);
1287
e_dbus_authenticator_emit_server_error (mediator->priv->dbus_interface, name, error->message);