1 /*
2 * Copyright (C) 2008 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General
15 * Public License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307, USA.
18 *
19 * Author: David Zeuthen <davidz@redhat.com>
20 */
21
22 #include "config.h"
23
24 #include <polkit/polkitprivate.h>
25
26 #include "polkitagentlistener.h"
27
28 /**
29 * SECTION:polkitagentlistener
30 * @title: PolkitAgentListener
31 * @short_description: Abstract base class for Authentication Agents
32 * @stability: Unstable
33 *
34 * #PolkitAgentListener is an abstract base class used for implementing authentication
35 * agents. To implement an authentication agent, simply subclass #PolkitAgentListener and
36 * implement the @initiate_authentication and @initiate_authentication_finish methods.
37 *
38 * Typically authentication agents use #PolkitAgentSession to
39 * authenticate users (via passwords) and communicate back the
40 * authentication result to the PolicyKit daemon.
41 *
42 * To register a #PolkitAgentListener with the PolicyKit daemon, use
43 * polkit_agent_listener_register() or
44 * polkit_agent_listener_register_with_options().
45 */
46
47 typedef struct
48 {
49 GObject parent_instance;
50
51 GDBusConnection *system_bus;
52 guint auth_agent_registration_id;
53
54 GDBusInterfaceInfo *interface_info;
55
56 PolkitAuthority *authority;
57 gulong notify_owner_handler_id;
58
59 gboolean is_registered;
60
61 PolkitAgentListener *listener;
62
63 GVariant *registration_options;
64
65 PolkitSubject *subject;
66 gchar *object_path;
67
68 GHashTable *cookie_to_pending_auth;
69
70 GThread *thread;
71 GError *thread_initialization_error;
72 gboolean thread_initialized;
73 GMainContext *thread_context;
74 GMainLoop *thread_loop;
75 } Server;
76
77 static void
server_free(Server * server)78 server_free (Server *server)
79 {
80 if (server->is_registered)
81 {
82 GError *error;
83 error = NULL;
84 if (!polkit_authority_unregister_authentication_agent_sync (server->authority,
85 server->subject,
86 server->object_path,
87 NULL,
88 &error))
89 {
90 g_warning ("Error unregistering authentication agent: %s", error->message);
91 g_error_free (error);
92 }
93 }
94
95 if (server->thread_initialization_error != NULL)
96 g_error_free (server->thread_initialization_error);
97
98 if (server->thread_context != NULL)
99 g_main_context_unref (server->thread_context);
100
101 if (server->thread_loop != NULL)
102 g_main_loop_unref (server->thread_loop);
103
104 if (server->interface_info != NULL)
105 g_dbus_interface_info_unref (server->interface_info);
106
107 if (server->registration_options != NULL)
108 g_variant_unref (server->registration_options);
109
110 if (server->listener != NULL)
111 g_object_unref (server->listener);
112
113 if (server->auth_agent_registration_id > 0)
114 g_dbus_connection_unregister_object (server->system_bus, server->auth_agent_registration_id);
115
116 if (server->notify_owner_handler_id > 0)
117 g_signal_handler_disconnect (server->authority, server->notify_owner_handler_id);
118
119 if (server->authority != NULL)
120 g_object_unref (server->authority);
121
122 if (server->system_bus != NULL)
123 g_object_unref (server->system_bus);
124
125 if (server->cookie_to_pending_auth != NULL)
126 g_hash_table_unref (server->cookie_to_pending_auth);
127
128 if (server->subject != NULL)
129 g_object_unref (server->subject);
130
131 g_free (server->object_path);
132
133 g_free (server);
134 }
135
136 static gboolean
server_register(Server * server,GError ** error)137 server_register (Server *server,
138 GError **error)
139 {
140 GError *local_error;
141 gboolean ret;
142 const gchar *locale;
143
144 ret = FALSE;
145
146 locale = g_getenv ("LANG");
147 if (locale == NULL)
148 locale = "en_US.UTF-8";
149
150 local_error = NULL;
151 if (!polkit_authority_register_authentication_agent_with_options_sync (server->authority,
152 server->subject,
153 locale,
154 server->object_path,
155 server->registration_options,
156 NULL,
157 &local_error))
158 {
159 g_propagate_error (error, local_error);
160 }
161 else
162 {
163 server->is_registered = TRUE;
164 ret = TRUE;
165 }
166
167 return ret;
168 }
169
170 static void
on_notify_authority_owner(GObject * object,GParamSpec * pspec,gpointer user_data)171 on_notify_authority_owner (GObject *object,
172 GParamSpec *pspec,
173 gpointer user_data)
174 {
175 Server *server = user_data;
176 gchar *owner;
177
178 owner = polkit_authority_get_owner (server->authority);
179 if (owner == NULL)
180 {
181 g_debug ("PolicyKit daemon disconnected from the bus.\n");
182
183 if (server->is_registered)
184 g_debug ("We are no longer a registered authentication agent.\n");
185
186 server->is_registered = FALSE;
187 }
188 else
189 {
190 /* only register if there is a name owner */
191 if (!server->is_registered)
192 {
193 GError *error;
194
195 g_debug ("PolicyKit daemon reconnected to bus.\n");
196 g_debug ("Attempting to re-register as an authentication agent.\n");
197
198 error = NULL;
199 if (server_register (server, &error))
200 {
201 g_debug ("We are now a registered authentication agent.\n");
202 }
203 else
204 {
205 g_debug ("Failed to register as an authentication agent: %s\n", error->message);
206 g_error_free (error);
207 }
208 }
209 }
210 g_free (owner);
211 }
212
213 static gboolean
server_init_sync(Server * server,GCancellable * cancellable,GError ** error)214 server_init_sync (Server *server,
215 GCancellable *cancellable,
216 GError **error)
217 {
218 gboolean ret;
219
220 ret = FALSE;
221
222 server->system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, error);
223 if (server->system_bus == NULL)
224 goto out;
225
226 server->authority = polkit_authority_get_sync (cancellable, error);
227 if (server->authority == NULL)
228 goto out;
229
230 /* the only use of this proxy is to re-register with the polkit daemon
231 * if it jumps off the bus and comes back (which is useful for debugging)
232 */
233 server->notify_owner_handler_id = g_signal_connect (server->authority,
234 "notify::owner",
235 G_CALLBACK (on_notify_authority_owner),
236 server);
237
238 ret = TRUE;
239
240 out:
241 return ret;
242 }
243
244 static Server *
server_new(PolkitSubject * subject,const gchar * object_path,GCancellable * cancellable,GError ** error)245 server_new (PolkitSubject *subject,
246 const gchar *object_path,
247 GCancellable *cancellable,
248 GError **error)
249 {
250 Server *server;
251
252 server = g_new0 (Server, 1);
253 server->subject = g_object_ref (subject);
254 server->object_path = object_path != NULL ? g_strdup (object_path) :
255 g_strdup ("/org/freedesktop/PolicyKit1/AuthenticationAgent");
256 server->cookie_to_pending_auth = g_hash_table_new (g_str_hash, g_str_equal);
257
258 if (!server_init_sync (server, cancellable, error))
259 {
260 server_free (server);
261 return NULL;
262 }
263
264 return server;
265 }
266
267 static void auth_agent_handle_begin_authentication (Server *server,
268 GVariant *parameters,
269 GDBusMethodInvocation *invocation);
270
271 static void auth_agent_handle_cancel_authentication (Server *server,
272 GVariant *parameters,
273 GDBusMethodInvocation *invocation);
274
275 static void
auth_agent_handle_method_call(GDBusConnection * connection,const gchar * sender,const gchar * object_path,const gchar * interface_name,const gchar * method_name,GVariant * parameters,GDBusMethodInvocation * invocation,gpointer user_data)276 auth_agent_handle_method_call (GDBusConnection *connection,
277 const gchar *sender,
278 const gchar *object_path,
279 const gchar *interface_name,
280 const gchar *method_name,
281 GVariant *parameters,
282 GDBusMethodInvocation *invocation,
283 gpointer user_data)
284 {
285 Server *server = user_data;
286
287 /* The shipped D-Bus policy also ensures that only uid 0 can invoke
288 * methods on our interface. So no need to check the caller.
289 */
290
291 if (g_strcmp0 (method_name, "BeginAuthentication") == 0)
292 auth_agent_handle_begin_authentication (server, parameters, invocation);
293 else if (g_strcmp0 (method_name, "CancelAuthentication") == 0)
294 auth_agent_handle_cancel_authentication (server, parameters, invocation);
295 else
296 g_assert_not_reached ();
297 }
298
299 static const gchar *auth_agent_introspection_data =
300 "<node>"
301 " <interface name='org.freedesktop.PolicyKit1.AuthenticationAgent'>"
302 " <method name='BeginAuthentication'>"
303 " <arg type='s' name='action_id' direction='in'/>"
304 " <arg type='s' name='message' direction='in'/>"
305 " <arg type='s' name='icon_name' direction='in'/>"
306 " <arg type='a{ss}' name='details' direction='in'/>"
307 " <arg type='s' name='cookie' direction='in'/>"
308 " <arg type='a(sa{sv})' name='identities' direction='in'/>"
309 " </method>"
310 " <method name='CancelAuthentication'>"
311 " <arg type='s' name='cookie' direction='in'/>"
312 " </method>"
313 " </interface>"
314 "</node>";
315
316 static const GDBusInterfaceVTable auth_agent_vtable =
317 {
318 auth_agent_handle_method_call,
319 NULL, /* _handle_get_property */
320 NULL /* _handle_set_property */
321 };
322
323 static gboolean
server_export_object(Server * server,GError ** error)324 server_export_object (Server *server,
325 GError **error)
326 {
327 gboolean ret;
328 ret = FALSE;
329 server->auth_agent_registration_id = g_dbus_connection_register_object (server->system_bus,
330 server->object_path,
331 server->interface_info,
332 &auth_agent_vtable,
333 server,
334 NULL, /* user_data GDestroyNotify */
335 error);
336 if (server->auth_agent_registration_id > 0)
337 ret = TRUE;
338 return ret;
339 }
340
341 static gpointer
server_thread_func(gpointer user_data)342 server_thread_func (gpointer user_data)
343 {
344 Server *server = user_data;
345
346 server->thread_context = g_main_context_new ();
347 server->thread_loop = g_main_loop_new (server->thread_context, FALSE);
348
349 g_main_context_push_thread_default (server->thread_context);
350
351 if (!server_export_object (server, &server->thread_initialization_error))
352 {
353 server->thread_initialized = TRUE;
354 goto out;
355 }
356
357 server->thread_initialized = TRUE;
358
359 g_main_loop_run (server->thread_loop);
360
361 out:
362 g_main_context_pop_thread_default (server->thread_context);
363 return NULL;
364 }
365
366 /**
367 * polkit_agent_listener_register_with_options:
368 * @listener: A #PolkitAgentListener.
369 * @flags: A set of flags from the #PolkitAgentRegisterFlags enumeration.
370 * @subject: The subject to become an authentication agent for, typically a #PolkitUnixSession object.
371 * @object_path: The D-Bus object path to use for the authentication agent or %NULL for the default object path.
372 * @options: (allow-none): A #GVariant with options or %NULL.
373 * @cancellable: A #GCancellable or %NULL.
374 * @error: Return location for error.
375 *
376 * Like polkit_agent_listener_register() but takes options to influence registration. See the
377 * <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgentWithOptions">RegisterAuthenticationAgentWithOptions()</link> D-Bus method for details.
378 *
379 * Returns: (transfer full): %NULL if @error is set, otherwise a
380 * registration handle that can be used with
381 * polkit_agent_listener_unregister().
382 */
383 gpointer
polkit_agent_listener_register_with_options(PolkitAgentListener * listener,PolkitAgentRegisterFlags flags,PolkitSubject * subject,const gchar * object_path,GVariant * options,GCancellable * cancellable,GError ** error)384 polkit_agent_listener_register_with_options (PolkitAgentListener *listener,
385 PolkitAgentRegisterFlags flags,
386 PolkitSubject *subject,
387 const gchar *object_path,
388 GVariant *options,
389 GCancellable *cancellable,
390 GError **error)
391 {
392 Server *server;
393 GDBusNodeInfo *node_info;
394
395 g_return_val_if_fail (POLKIT_AGENT_IS_LISTENER (listener), NULL);
396 g_return_val_if_fail (POLKIT_IS_SUBJECT (subject), NULL);
397 g_return_val_if_fail (object_path == NULL || g_variant_is_object_path (object_path), NULL);
398 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
399 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
400
401 if (object_path == NULL)
402 object_path = "/org/freedesktop/PolicyKit1/AuthenticationAgent";
403
404 server = server_new (subject, object_path, cancellable, error);
405 if (server == NULL)
406 goto out;
407
408 node_info = g_dbus_node_info_new_for_xml (auth_agent_introspection_data, error);
409 if (node_info == NULL)
410 {
411 server_free (server);
412 server = NULL;
413 goto out;
414 }
415 server->interface_info = g_dbus_interface_info_ref (g_dbus_node_info_lookup_interface (node_info, "org.freedesktop.PolicyKit1.AuthenticationAgent"));
416 g_dbus_node_info_unref (node_info);
417
418 server->listener = g_object_ref (listener);
419
420 server->registration_options = options != NULL ? g_variant_ref_sink (options) : NULL;
421
422 if (flags & POLKIT_AGENT_REGISTER_FLAGS_RUN_IN_THREAD)
423 {
424 server->thread = g_thread_try_new ("polkit agent listener",
425 server_thread_func, server, error);
426 if (server->thread == NULL)
427 {
428 server_free (server);
429 server = NULL;
430 goto out;
431 }
432
433 /* wait for the thread to export and object (TODO: probably use a condition variable instead) */
434 while (!server->thread_initialized)
435 g_thread_yield ();
436 if (server->thread_initialization_error != NULL)
437 {
438 g_propagate_error (error, server->thread_initialization_error);
439 server->thread_initialization_error = NULL;
440 g_thread_join (server->thread);
441 server_free (server);
442 server = NULL;
443 goto out;
444 }
445 }
446 else
447 {
448 if (!server_export_object (server, error))
449 {
450 server_free (server);
451 server = NULL;
452 goto out;
453 }
454 }
455
456 if (!server_register (server, error))
457 {
458 server_free (server);
459 server = NULL;
460 goto out;
461 }
462
463 out:
464 return server;
465 }
466
467 /**
468 * polkit_agent_listener_register:
469 * @listener: A #PolkitAgentListener.
470 * @flags: A set of flags from the #PolkitAgentRegisterFlags enumeration.
471 * @subject: The subject to become an authentication agent for, typically a #PolkitUnixSession object.
472 * @object_path: The D-Bus object path to use for the authentication agent or %NULL for the default object path.
473 * @cancellable: A #GCancellable or %NULL.
474 * @error: Return location for error.
475 *
476 * Registers @listener with the PolicyKit daemon as an authentication
477 * agent for @subject. This is implemented by registering a D-Bus
478 * object at @object_path on the unique name assigned by the system
479 * message bus.
480 *
481 * Whenever the PolicyKit daemon needs to authenticate a processes
482 * that is related to @subject, the methods
483 * polkit_agent_listener_initiate_authentication() and
484 * polkit_agent_listener_initiate_authentication_finish() will be
485 * invoked on @listener.
486 *
487 * Note that registration of an authentication agent can fail; for
488 * example another authentication agent may already be registered for
489 * @subject.
490 *
491 * Note that the calling thread is blocked until a reply is received.
492 *
493 * Returns: (transfer full): %NULL if @error is set, otherwise a
494 * registration handle that can be used with
495 * polkit_agent_listener_unregister().
496 */
497 gpointer
polkit_agent_listener_register(PolkitAgentListener * listener,PolkitAgentRegisterFlags flags,PolkitSubject * subject,const gchar * object_path,GCancellable * cancellable,GError ** error)498 polkit_agent_listener_register (PolkitAgentListener *listener,
499 PolkitAgentRegisterFlags flags,
500 PolkitSubject *subject,
501 const gchar *object_path,
502 GCancellable *cancellable,
503 GError **error)
504 {
505 return polkit_agent_listener_register_with_options (listener, flags, subject, object_path, NULL, cancellable, error);
506 }
507
508 /**
509 * polkit_agent_listener_unregister:
510 * @registration_handle: A handle obtained from polkit_agent_listener_register().
511 *
512 * Unregisters @listener.
513 */
514 void
polkit_agent_listener_unregister(gpointer registration_handle)515 polkit_agent_listener_unregister (gpointer registration_handle)
516 {
517 Server *server = registration_handle;
518 if (server->thread != NULL)
519 {
520 g_main_loop_quit (server->thread_loop);
521 g_thread_join (server->thread);
522 }
523 server_free (server);
524 }
525
526
527 static void
listener_died(gpointer user_data,GObject * where_the_object_was)528 listener_died (gpointer user_data,
529 GObject *where_the_object_was)
530 {
531 Server *server = user_data;
532 server_free (server);
533 }
534
535 /**
536 * polkit_agent_register_listener:
537 * @listener: A #PolkitAgentListener.
538 * @subject: The subject to become an authentication agent for, typically a #PolkitUnixSession object.
539 * @object_path: The D-Bus object path to use for the authentication agent or %NULL for the default object path.
540 * @error: Return location for error.
541 *
542 * (deprecated)
543 */
544 gboolean
polkit_agent_register_listener(PolkitAgentListener * listener,PolkitSubject * subject,const gchar * object_path,GError ** error)545 polkit_agent_register_listener (PolkitAgentListener *listener,
546 PolkitSubject *subject,
547 const gchar *object_path,
548 GError **error)
549 {
550 Server *server;
551 gboolean ret;
552
553 ret = FALSE;
554
555 server = polkit_agent_listener_register (listener, POLKIT_AGENT_REGISTER_FLAGS_NONE, subject, object_path, NULL, error);
556 if (server == NULL)
557 goto out;
558
559 /* drop the ref that server took */
560 g_object_unref (server->listener);
561 /* take a weak ref and kill server when listener dies */
562 g_object_weak_ref (G_OBJECT (server->listener), listener_died, server);
563
564 ret = TRUE;
565
566 out:
567 return ret;
568 }
569
570 typedef struct
571 {
572 gchar *cookie;
573 GHashTable *cookie_to_pending_auth;
574 GDBusMethodInvocation *invocation;
575 GCancellable *cancellable;
576 } AuthData;
577
578 static void
auth_data_free(AuthData * data)579 auth_data_free (AuthData *data)
580 {
581 g_free (data->cookie);
582 g_object_unref (data->invocation);
583 g_object_unref (data->cancellable);
584 g_hash_table_unref (data->cookie_to_pending_auth);
585 g_free (data);
586 }
587
588 /* ---------------------------------------------------------------------------------------------------- */
589
590 static void
auth_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)591 auth_cb (GObject *source_object,
592 GAsyncResult *res,
593 gpointer user_data)
594 {
595 AuthData *data = user_data;
596 GError *error;
597
598 error = NULL;
599 if (!polkit_agent_listener_initiate_authentication_finish (POLKIT_AGENT_LISTENER (source_object),
600 res,
601 &error))
602 {
603 g_dbus_method_invocation_return_gerror (data->invocation, error);
604 g_error_free (error);
605 }
606 else
607 {
608 g_dbus_method_invocation_return_value (data->invocation, NULL);
609 }
610
611 g_hash_table_remove (data->cookie_to_pending_auth, data->cookie);
612
613 auth_data_free (data);
614 }
615
616 static void
auth_agent_handle_begin_authentication(Server * server,GVariant * parameters,GDBusMethodInvocation * invocation)617 auth_agent_handle_begin_authentication (Server *server,
618 GVariant *parameters,
619 GDBusMethodInvocation *invocation)
620 {
621 const gchar *action_id;
622 const gchar *message;
623 const gchar *icon_name;
624 GVariant *details_gvariant;
625 const gchar *cookie;
626 GVariant *identities_gvariant;
627 GList *identities;
628 PolkitDetails *details;
629 GVariantIter iter;
630 GVariant *child;
631 guint n;
632 AuthData *data;
633
634 identities = NULL;
635 details = NULL;
636
637 g_variant_get (parameters,
638 "(&s&s&s@a{ss}&s@a(sa{sv}))",
639 &action_id,
640 &message,
641 &icon_name,
642 &details_gvariant,
643 &cookie,
644 &identities_gvariant);
645
646 details = polkit_details_new_for_gvariant (details_gvariant);
647
648 g_variant_iter_init (&iter, identities_gvariant);
649 n = 0;
650 while ((child = g_variant_iter_next_value (&iter)) != NULL)
651 {
652 PolkitIdentity *identity;
653 GError *error;
654 error = NULL;
655 identity = polkit_identity_new_for_gvariant (child, &error);
656 g_variant_unref (child);
657
658 if (identity == NULL)
659 {
660 g_prefix_error (&error, "Error extracting identity %d: ", n);
661 g_dbus_method_invocation_return_gerror (invocation, error);
662 g_error_free (error);
663 goto out;
664 }
665 n++;
666
667 identities = g_list_prepend (identities, identity);
668 }
669 identities = g_list_reverse (identities);
670
671 data = g_new0 (AuthData, 1);
672 data->cookie_to_pending_auth = g_hash_table_ref (server->cookie_to_pending_auth);
673 data->cookie = g_strdup (cookie);
674 data->invocation = g_object_ref (invocation);
675 data->cancellable = g_cancellable_new ();
676
677 g_hash_table_insert (server->cookie_to_pending_auth, (gpointer) cookie, data);
678
679 polkit_agent_listener_initiate_authentication (server->listener,
680 action_id,
681 message,
682 icon_name,
683 details,
684 cookie,
685 identities,
686 data->cancellable,
687 auth_cb,
688 data);
689
690 out:
691 g_list_foreach (identities, (GFunc) g_object_unref, NULL);
692 g_list_free (identities);
693 g_object_unref (details);
694 g_variant_unref (details_gvariant);
695 g_variant_unref (identities_gvariant);
696 }
697
698 /* ---------------------------------------------------------------------------------------------------- */
699
700 static void
auth_agent_handle_cancel_authentication(Server * server,GVariant * parameters,GDBusMethodInvocation * invocation)701 auth_agent_handle_cancel_authentication (Server *server,
702 GVariant *parameters,
703 GDBusMethodInvocation *invocation)
704 {
705 AuthData *data;
706 const gchar *cookie;
707
708 g_variant_get (parameters,
709 "(&s)",
710 &cookie);
711
712 data = g_hash_table_lookup (server->cookie_to_pending_auth, cookie);
713 if (data == NULL)
714 {
715 g_dbus_method_invocation_return_error (invocation,
716 POLKIT_ERROR,
717 POLKIT_ERROR_FAILED,
718 "No pending authentication request for cookie '%s'",
719 cookie);
720 }
721 else
722 {
723 g_cancellable_cancel (data->cancellable);
724 g_dbus_method_invocation_return_value (invocation, NULL);
725 }
726 }
727
728 /* ---------------------------------------------------------------------------------------------------- */
729
730 G_DEFINE_ABSTRACT_TYPE (PolkitAgentListener, polkit_agent_listener, G_TYPE_OBJECT);
731
732 static void
polkit_agent_listener_init(PolkitAgentListener * listener)733 polkit_agent_listener_init (PolkitAgentListener *listener)
734 {
735 }
736
737 static void
polkit_agent_listener_class_init(PolkitAgentListenerClass * klass)738 polkit_agent_listener_class_init (PolkitAgentListenerClass *klass)
739 {
740 }
741
742 /**
743 * polkit_agent_listener_initiate_authentication:
744 * @listener: A #PolkitAgentListener.
745 * @action_id: The action to authenticate for.
746 * @message: The message to present to the user.
747 * @icon_name: A themed icon name representing the action or %NULL.
748 * @details: Details describing the action.
749 * @cookie: The cookie for the authentication request.
750 * @identities: (element-type Polkit.Identity): A list of #PolkitIdentity objects that the user can choose to authenticate as.
751 * @cancellable: A #GCancellable.
752 * @callback: Function to call when the user is done authenticating.
753 * @user_data: Data to pass to @callback.
754 *
755 * Called on a registered authentication agent (see
756 * polkit_agent_listener_register()) when the user owning the session
757 * needs to prove he is one of the identities listed in @identities.
758 *
759 * When the user is done authenticating (for example by dismissing an
760 * authentication dialog or by successfully entering a password or
761 * otherwise proving the user is one of the identities in
762 * @identities), @callback will be invoked. The caller then calls
763 * polkit_agent_listener_initiate_authentication_finish() to get the
764 * result.
765 *
766 * #PolkitAgentListener derived subclasses imlementing this method
767 * <emphasis>MUST</emphasis> not ignore @cancellable; callers of this
768 * function can and will use it. Additionally, @callback must be
769 * invoked in the <link
770 * linkend="g-main-context-push-thread-default">thread-default main
771 * loop</link> of the thread that this method is called from.
772 */
773 void
polkit_agent_listener_initiate_authentication(PolkitAgentListener * listener,const gchar * action_id,const gchar * message,const gchar * icon_name,PolkitDetails * details,const gchar * cookie,GList * identities,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)774 polkit_agent_listener_initiate_authentication (PolkitAgentListener *listener,
775 const gchar *action_id,
776 const gchar *message,
777 const gchar *icon_name,
778 PolkitDetails *details,
779 const gchar *cookie,
780 GList *identities,
781 GCancellable *cancellable,
782 GAsyncReadyCallback callback,
783 gpointer user_data)
784 {
785 g_return_if_fail (POLKIT_AGENT_IS_LISTENER (listener));
786 g_return_if_fail (details == NULL || POLKIT_IS_DETAILS (details));
787 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
788 g_return_if_fail (action_id != NULL);
789 g_return_if_fail (message != NULL);
790 g_return_if_fail (cookie != NULL);
791 g_return_if_fail (identities != NULL);
792 POLKIT_AGENT_LISTENER_GET_CLASS (listener)->initiate_authentication (listener,
793 action_id,
794 message,
795 icon_name,
796 details,
797 cookie,
798 identities,
799 cancellable,
800 callback,
801 user_data);
802 }
803
804 /**
805 * polkit_agent_listener_initiate_authentication_finish:
806 * @listener: A #PolkitAgentListener.
807 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to polkit_agent_listener_initiate_authentication().
808 * @error: Return location for error.
809 *
810 * Finishes an authentication request from the PolicyKit daemon, see
811 * polkit_agent_listener_initiate_authentication() for details.
812 *
813 * Returns: %TRUE if @error is set.
814 **/
815 gboolean
polkit_agent_listener_initiate_authentication_finish(PolkitAgentListener * listener,GAsyncResult * res,GError ** error)816 polkit_agent_listener_initiate_authentication_finish (PolkitAgentListener *listener,
817 GAsyncResult *res,
818 GError **error)
819 {
820 g_return_val_if_fail (POLKIT_AGENT_IS_LISTENER (listener), FALSE);
821 g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
822 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
823 return POLKIT_AGENT_LISTENER_GET_CLASS (listener)->initiate_authentication_finish (listener,
824 res,
825 error);
826 }
827
828