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