PolicyKit: Branch 'master'

David Zeuthen david at kemper.freedesktop.org
Thu Apr 12 11:06:53 PDT 2012


 docs/man/pkttyagent.xml                                                |   11 
 docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml |   18 +
 docs/polkit/polkit-1-sections.txt                                      |    4 
 src/polkit/polkitauthority.c                                           |  164 ++++++++++
 src/polkit/polkitauthority.h                                           |   22 +
 src/polkitagent/polkitagentlistener.c                                  |   98 ++++-
 src/polkitagent/polkitagentlistener.h                                  |    8 
 src/polkitbackend/polkitbackendauthority.c                             |   70 ++++
 src/polkitbackend/polkitbackendauthority.h                             |    2 
 src/polkitbackend/polkitbackendinteractiveauthority.c                  |   52 ++-
 src/programs/pkttyagent.c                                              |   31 +
 11 files changed, 427 insertions(+), 53 deletions(-)

New commits:
commit 2dd284eb425535445f0be6e9dd7d45e8ccd3ffa6
Author: David Zeuthen <davidz at redhat.com>
Date:   Thu Apr 12 13:54:27 2012 -0400

    Make it possible to influence agent registration with an a{sv} parameter
    
    Additionally, add a "fallback" option. Also add support in this in the
    pkttyagent(1) program.
    
    This slightly breaks libpolkit-backend API by adding a GVariant* param
    to one of the class vfuncs... but that API is already declared
    unstable so that's fine.
    
    Signed-off-by: David Zeuthen <davidz at redhat.com>

diff --git a/docs/man/pkttyagent.xml b/docs/man/pkttyagent.xml
index f0f328e..a5bab8a 100644
--- a/docs/man/pkttyagent.xml
+++ b/docs/man/pkttyagent.xml
@@ -56,6 +56,12 @@
         </arg>
       </group>
 
+      <group>
+        <arg choice="plain">
+          <option>--fallback</option>
+        </arg>
+      </group>
+
     </cmdsynopsis>
 
   </refsynopsisdiv>
@@ -78,6 +84,11 @@
       program. This file descriptor will then be closed when the
       authentication agent has been successfully registered.
     </para>
+    <para>
+      If <option>--fallback</option> is used, the textual
+      authentication agent will not replace an existing authentication
+      agent.
+    </para>
   </refsect1>
 
   <refsect1 id="pkttyagent-return-value">
diff --git a/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml b/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml
index d4894f5..49173f8 100644
--- a/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml
+++ b/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml
@@ -34,6 +34,10 @@ Structure    <link linkend="eggdbus-struct-TemporaryAuthorization">TemporaryAuth
 <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent">RegisterAuthenticationAgent</link>      (IN  <link linkend="eggdbus-struct-Subject">Subject</link>                        subject,
                                   IN  String                         locale,
                                   IN  String                         object_path)
+<link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgentWithOptions">RegisterAuthenticationAgentWithOptions</link> (IN  <link linkend="eggdbus-struct-Subject">Subject</link>                  subject,
+                                  IN  String                         locale,
+                                  IN  String                         object_path,
+                                  IN  Dict&lt;String,Variant&gt;     options)
 <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.UnregisterAuthenticationAgent">UnregisterAuthenticationAgent</link>    (IN  <link linkend="eggdbus-struct-Subject">Subject</link>                        subject,
                                   IN  String                         object_path)
 <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse">AuthenticationAgentResponse</link>      (IN  String                         cookie,
@@ -724,6 +728,20 @@ The object path of authentication agent object on the unique name of the caller.
   </varlistentry>
 </variablelist>
     </refsect2>
+
+    <refsect2 role="function" id="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgentWithOptions">
+      <title>RegisterAuthenticationAgentWithOptions ()</title>
+    <programlisting>
+RegisterAuthenticationAgent (IN  <link linkend="eggdbus-struct-Subject">Subject</link>  subject,
+                             IN  String                   locale,
+                             IN  String                   object_path,
+                             IN  Dict&lt;String,Variant&gt;     options)
+    </programlisting>
+    <para>
+<para>Like <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent">RegisterAuthenticationAgent</link> but takes additional options. If the option <literal>fallback</literal> (of type <literal>Boolean</literal>) is TRUE, then the authentcation agent will only be used as a fallback, e.g. if another agent (without the <literal>fallback</literal> option set TRUE) is available, it will be used instead.</para>
+    </para>
+    </refsect2>
+
     <refsect2 role="function" id="eggdbus-method-org.freedesktop.PolicyKit1.Authority.UnregisterAuthenticationAgent">
       <title>UnregisterAuthenticationAgent ()</title>
     <programlisting>
diff --git a/docs/polkit/polkit-1-sections.txt b/docs/polkit/polkit-1-sections.txt
index ff6a301..3881004 100644
--- a/docs/polkit/polkit-1-sections.txt
+++ b/docs/polkit/polkit-1-sections.txt
@@ -38,6 +38,9 @@ polkit_authority_enumerate_actions_sync
 polkit_authority_register_authentication_agent
 polkit_authority_register_authentication_agent_finish
 polkit_authority_register_authentication_agent_sync
+polkit_authority_register_authentication_agent_with_options
+polkit_authority_register_authentication_agent_with_options_finish
+polkit_authority_register_authentication_agent_with_options_sync
 polkit_authority_unregister_authentication_agent
 polkit_authority_unregister_authentication_agent_finish
 polkit_authority_unregister_authentication_agent_sync
@@ -394,6 +397,7 @@ polkit_agent_listener_initiate_authentication
 polkit_agent_listener_initiate_authentication_finish
 PolkitAgentRegisterFlags
 polkit_agent_listener_register
+polkit_agent_listener_register_with_options
 polkit_agent_listener_unregister
 <SUBSECTION Standard>
 POLKIT_AGENT_LISTENER
diff --git a/src/polkit/polkitauthority.c b/src/polkit/polkitauthority.c
index 468421e..9947cf3 100644
--- a/src/polkit/polkitauthority.c
+++ b/src/polkit/polkitauthority.c
@@ -1167,6 +1167,170 @@ polkit_authority_register_authentication_agent_sync (PolkitAuthority     *author
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
+ * polkit_authority_register_authentication_agent_with_options:
+ * @authority: A #PolkitAuthority.
+ * @subject: The subject the authentication agent is for, typically a #PolkitUnixSession object.
+ * @locale: The locale of the authentication agent.
+ * @object_path: The object path for the authentication agent.
+ * @options: (allow-none): A #GVariant with options or %NULL.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
+ * @user_data: The data to pass to @callback.
+ *
+ * Asynchronously registers an authentication agent.
+ *
+ * When the operation is finished, @callback will be invoked in the
+ * <link linkend="g-main-context-push-thread-default">thread-default
+ * main loop</link> of the thread you are calling this method
+ * from. You can then call
+ * polkit_authority_register_authentication_agent_with_options_finish() to get the
+ * result of the operation.
+ **/
+void
+polkit_authority_register_authentication_agent_with_options (PolkitAuthority      *authority,
+                                                             PolkitSubject        *subject,
+                                                             const gchar          *locale,
+                                                             const gchar          *object_path,
+                                                             GVariant             *options,
+                                                             GCancellable         *cancellable,
+                                                             GAsyncReadyCallback   callback,
+                                                             gpointer              user_data)
+{
+  GVariant *subject_value;
+
+  g_return_if_fail (POLKIT_IS_AUTHORITY (authority));
+  g_return_if_fail (POLKIT_IS_SUBJECT (subject));
+  g_return_if_fail (locale != NULL);
+  g_return_if_fail (g_variant_is_object_path (object_path));
+  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+  subject_value = polkit_subject_to_gvariant (subject);
+  g_variant_ref_sink (subject_value);
+  if (options != NULL)
+    {
+      g_dbus_proxy_call (authority->proxy,
+                         "RegisterAuthenticationAgentWithOptions",
+                         g_variant_new ("(@(sa{sv})ss at a{sv})",
+                                        subject_value,
+                                        locale,
+                                        object_path,
+                                        options),
+                         G_DBUS_CALL_FLAGS_NONE,
+                         -1,
+                         cancellable,
+                         generic_async_cb,
+                         g_simple_async_result_new (G_OBJECT (authority),
+                                                    callback,
+                                                    user_data,
+                                                    polkit_authority_register_authentication_agent_with_options));
+    }
+  else
+    {
+      g_dbus_proxy_call (authority->proxy,
+                         "RegisterAuthenticationAgent",
+                         g_variant_new ("(@(sa{sv})ss)",
+                                        subject_value,
+                                        locale,
+                                        object_path),
+                         G_DBUS_CALL_FLAGS_NONE,
+                         -1,
+                         cancellable,
+                         generic_async_cb,
+                         g_simple_async_result_new (G_OBJECT (authority),
+                                                    callback,
+                                                    user_data,
+                                                    polkit_authority_register_authentication_agent_with_options));
+    }
+  g_variant_unref (subject_value);
+}
+
+/**
+ * polkit_authority_register_authentication_agent_with_options_finish:
+ * @authority: A #PolkitAuthority.
+ * @res: A #GAsyncResult obtained from the callback.
+ * @error: (allow-none): Return location for error or %NULL.
+ *
+ * Finishes registering an authentication agent.
+ *
+ * Returns: %TRUE if the authentication agent was successfully registered, %FALSE if @error is set.
+ **/
+gboolean
+polkit_authority_register_authentication_agent_with_options_finish (PolkitAuthority *authority,
+                                                                    GAsyncResult    *res,
+                                                                    GError         **error)
+{
+  gboolean ret;
+  GVariant *value;
+  GAsyncResult *_res;
+
+  g_return_val_if_fail (POLKIT_IS_AUTHORITY (authority), FALSE);
+  g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  ret = FALSE;
+
+  g_warn_if_fail (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (res)) == polkit_authority_register_authentication_agent_with_options);
+  _res = G_ASYNC_RESULT (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
+
+  value = g_dbus_proxy_call_finish (authority->proxy, _res, error);
+  if (value == NULL)
+    goto out;
+  ret = TRUE;
+  g_variant_unref (value);
+
+ out:
+  return ret;
+}
+
+
+/**
+ * polkit_authority_register_authentication_agent_with_options_sync:
+ * @authority: A #PolkitAuthority.
+ * @subject: The subject the authentication agent is for, typically a #PolkitUnixSession object.
+ * @locale: The locale of the authentication agent.
+ * @object_path: The object path for the authentication agent.
+ * @options: (allow-none): A #GVariant with options or %NULL.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @error: (allow-none): Return location for error or %NULL.
+ *
+ * Registers an authentication agent. The calling thread is blocked
+ * until a reply is received. See
+ * polkit_authority_register_authentication_agent_with_options() for the
+ * asynchronous version.
+ *
+ * Returns: %TRUE if the authentication agent was successfully registered, %FALSE if @error is set.
+ **/
+gboolean
+polkit_authority_register_authentication_agent_with_options_sync (PolkitAuthority     *authority,
+                                                                  PolkitSubject       *subject,
+                                                                  const gchar         *locale,
+                                                                  const gchar         *object_path,
+                                                                  GVariant            *options,
+                                                                  GCancellable        *cancellable,
+                                                                  GError             **error)
+{
+  gboolean ret;
+  CallSyncData *data;
+
+  g_return_val_if_fail (POLKIT_IS_AUTHORITY (authority), FALSE);
+  g_return_val_if_fail (POLKIT_IS_SUBJECT (subject), FALSE);
+  g_return_val_if_fail (locale != NULL, FALSE);
+  g_return_val_if_fail (g_variant_is_object_path (object_path), FALSE);
+  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  data = call_sync_new ();
+  polkit_authority_register_authentication_agent_with_options (authority, subject, locale, object_path, options, cancellable, call_sync_cb, data);
+  call_sync_block (data);
+  ret = polkit_authority_register_authentication_agent_with_options_finish (authority, data->res, error);
+  call_sync_free (data);
+
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
  * polkit_authority_unregister_authentication_agent:
  * @authority: A #PolkitAuthority.
  * @subject: The subject the authentication agent is for, typically a #PolkitUnixSession object.
diff --git a/src/polkit/polkitauthority.h b/src/polkit/polkitauthority.h
index edd8a62..921b712 100644
--- a/src/polkit/polkitauthority.h
+++ b/src/polkit/polkitauthority.h
@@ -83,6 +83,14 @@ gboolean                   polkit_authority_register_authentication_agent_sync (
                                                                                 GCancellable        *cancellable,
                                                                                 GError             **error);
 
+gboolean                   polkit_authority_register_authentication_agent_with_options_sync (PolkitAuthority     *authority,
+                                                                                             PolkitSubject       *subject,
+                                                                                             const gchar         *locale,
+                                                                                             const gchar         *object_path,
+                                                                                             GVariant            *options,
+                                                                                             GCancellable        *cancellable,
+                                                                                             GError             **error);
+
 gboolean                   polkit_authority_unregister_authentication_agent_sync (PolkitAuthority     *authority,
                                                                                   PolkitSubject       *subject,
                                                                                   const gchar         *object_path,
@@ -142,10 +150,24 @@ void                       polkit_authority_register_authentication_agent (Polki
                                                                            GAsyncReadyCallback  callback,
                                                                            gpointer             user_data);
 
+
 gboolean                   polkit_authority_register_authentication_agent_finish (PolkitAuthority *authority,
                                                                                   GAsyncResult    *res,
                                                                                   GError         **error);
 
+gboolean                   polkit_authority_register_authentication_agent_with_options_finish (PolkitAuthority *authority,
+                                                                                               GAsyncResult    *res,
+                                                                                               GError         **error);
+
+void                       polkit_authority_register_authentication_agent_with_options (PolkitAuthority     *authority,
+                                                                                        PolkitSubject       *subject,
+                                                                                        const gchar         *locale,
+                                                                                        const gchar         *object_path,
+                                                                                        GVariant            *options,
+                                                                                        GCancellable        *cancellable,
+                                                                                        GAsyncReadyCallback  callback,
+                                                                                        gpointer             user_data);
+
 void                       polkit_authority_unregister_authentication_agent (PolkitAuthority     *authority,
                                                                              PolkitSubject       *subject,
                                                                              const gchar         *object_path,
diff --git a/src/polkitagent/polkitagentlistener.c b/src/polkitagent/polkitagentlistener.c
index dbbfd63..0d97501 100644
--- a/src/polkitagent/polkitagentlistener.c
+++ b/src/polkitagent/polkitagentlistener.c
@@ -43,7 +43,8 @@
  * evidence that the user is one of the requested identities.
  *
  * To register a #PolkitAgentListener with the PolicyKit daemon, use
- * polkit_agent_listener_register().
+ * polkit_agent_listener_register() or
+ * polkit_agent_listener_register_with_options().
  */
 
 typedef struct
@@ -62,6 +63,8 @@ typedef struct
 
   PolkitAgentListener *listener;
 
+  GVariant *registration_options;
+
   PolkitSubject *subject;
   gchar *object_path;
 
@@ -104,6 +107,9 @@ server_free (Server *server)
   if (server->interface_info != NULL)
     g_dbus_interface_info_unref (server->interface_info);
 
+  if (server->registration_options != NULL)
+    g_variant_unref (server->registration_options);
+
   if (server->listener != NULL)
     g_object_unref (server->listener);
 
@@ -143,12 +149,13 @@ server_register (Server   *server,
     locale = "en_US.UTF-8";
 
   local_error = NULL;
-  if (!polkit_authority_register_authentication_agent_sync (server->authority,
-                                                            server->subject,
-                                                            locale,
-                                                            server->object_path,
-                                                            NULL,
-                                                            &local_error))
+  if (!polkit_authority_register_authentication_agent_with_options_sync (server->authority,
+                                                                         server->subject,
+                                                                         locale,
+                                                                         server->object_path,
+                                                                         server->registration_options,
+                                                                         NULL,
+                                                                         &local_error))
     {
       g_warning ("Unable to register authentication agent: %s", local_error->message);
       g_propagate_error (error, local_error);
@@ -360,42 +367,30 @@ server_thread_func (gpointer user_data)
 }
 
 /**
- * polkit_agent_listener_register:
+ * polkit_agent_listener_register_with_options:
  * @listener: A #PolkitAgentListener.
  * @flags: A set of flags from the #PolkitAgentRegisterFlags enumeration.
  * @subject: The subject to become an authentication agent for, typically a #PolkitUnixSession object.
  * @object_path: The D-Bus object path to use for the authentication agent or %NULL for the default object path.
+ * @options: (allow-none): A #GVariant with options or %NULL.
  * @cancellable: A #GCancellable or %NULL.
  * @error: Return location for error.
  *
- * Registers @listener with the PolicyKit daemon as an authentication
- * agent for @subject. This is implemented by registering a D-Bus
- * object at @object_path on the unique name assigned by the system
- * message bus.
- *
- * Whenever the PolicyKit daemon needs to authenticate a processes
- * that is related to @subject, the methods
- * polkit_agent_listener_initiate_authentication() and
- * polkit_agent_listener_initiate_authentication_finish() will be
- * invoked on @listener.
- *
- * Note that registration of an authentication agent can fail; for
- * example another authentication agent may already be registered for
- * @subject.
- *
- * Note that the calling thread is blocked until a reply is received.
+ * Like polkit_agent_listener_register() but takes options to influence registration. See the
+ * <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgentWithOptions">RegisterAuthenticationAgentWithOptions()</link> D-Bus method for details.
  *
  * Returns: (transfer full): %NULL if @error is set, otherwise a
  * registration handle that can be used with
  * polkit_agent_listener_unregister().
  */
 gpointer
-polkit_agent_listener_register (PolkitAgentListener      *listener,
-                                PolkitAgentRegisterFlags  flags,
-                                PolkitSubject            *subject,
-                                const gchar              *object_path,
-                                GCancellable             *cancellable,
-                                GError                  **error)
+polkit_agent_listener_register_with_options (PolkitAgentListener      *listener,
+                                             PolkitAgentRegisterFlags  flags,
+                                             PolkitSubject            *subject,
+                                             const gchar              *object_path,
+                                             GVariant                 *options,
+                                             GCancellable             *cancellable,
+                                             GError                  **error)
 {
   Server *server;
   GDBusNodeInfo *node_info;
@@ -425,6 +420,8 @@ polkit_agent_listener_register (PolkitAgentListener      *listener,
 
   server->listener = g_object_ref (listener);
 
+  server->registration_options = options != NULL ? g_variant_ref_sink (options) : NULL;
+
   if (flags & POLKIT_AGENT_REGISTER_FLAGS_RUN_IN_THREAD)
     {
       server->thread = g_thread_create (server_thread_func,
@@ -472,6 +469,47 @@ polkit_agent_listener_register (PolkitAgentListener      *listener,
 }
 
 /**
+ * polkit_agent_listener_register:
+ * @listener: A #PolkitAgentListener.
+ * @flags: A set of flags from the #PolkitAgentRegisterFlags enumeration.
+ * @subject: The subject to become an authentication agent for, typically a #PolkitUnixSession object.
+ * @object_path: The D-Bus object path to use for the authentication agent or %NULL for the default object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error.
+ *
+ * Registers @listener with the PolicyKit daemon as an authentication
+ * agent for @subject. This is implemented by registering a D-Bus
+ * object at @object_path on the unique name assigned by the system
+ * message bus.
+ *
+ * Whenever the PolicyKit daemon needs to authenticate a processes
+ * that is related to @subject, the methods
+ * polkit_agent_listener_initiate_authentication() and
+ * polkit_agent_listener_initiate_authentication_finish() will be
+ * invoked on @listener.
+ *
+ * Note that registration of an authentication agent can fail; for
+ * example another authentication agent may already be registered for
+ * @subject.
+ *
+ * Note that the calling thread is blocked until a reply is received.
+ *
+ * Returns: (transfer full): %NULL if @error is set, otherwise a
+ * registration handle that can be used with
+ * polkit_agent_listener_unregister().
+ */
+gpointer
+polkit_agent_listener_register (PolkitAgentListener      *listener,
+                                PolkitAgentRegisterFlags  flags,
+                                PolkitSubject            *subject,
+                                const gchar              *object_path,
+                                GCancellable             *cancellable,
+                                GError                  **error)
+{
+  return polkit_agent_listener_register_with_options (listener, flags, subject, object_path, NULL, cancellable, error);
+}
+
+/**
  * polkit_agent_listener_unregister:
  * @registration_handle: A handle obtained from polkit_agent_listener_register().
  *
diff --git a/src/polkitagent/polkitagentlistener.h b/src/polkitagent/polkitagentlistener.h
index 191b265..c3cbcfb 100644
--- a/src/polkitagent/polkitagentlistener.h
+++ b/src/polkitagent/polkitagentlistener.h
@@ -134,6 +134,14 @@ gpointer  polkit_agent_listener_register                        (PolkitAgentList
                                                                  GCancellable             *cancellable,
                                                                  GError                  **error);
 
+gpointer  polkit_agent_listener_register_with_options           (PolkitAgentListener      *listener,
+                                                                 PolkitAgentRegisterFlags  flags,
+                                                                 PolkitSubject            *subject,
+                                                                 const gchar              *object_path,
+                                                                 GVariant                 *options,
+                                                                 GCancellable             *cancellable,
+                                                                 GError                  **error);
+
 void      polkit_agent_listener_unregister                      (gpointer                  registration_handle);
 
 G_END_DECLS
diff --git a/src/polkitbackend/polkitbackendauthority.c b/src/polkitbackend/polkitbackendauthority.c
index 44b7493..fd4f161 100644
--- a/src/polkitbackend/polkitbackendauthority.c
+++ b/src/polkitbackend/polkitbackendauthority.c
@@ -268,6 +268,7 @@ polkit_backend_authority_check_authorization_finish (PolkitBackendAuthority  *au
  * @subject: The subject the authentication agent wants to register for.
  * @locale: The locale of the authentication agent.
  * @object_path: The object path for the authentication agent.
+ * @options: A #GVariant with options or %NULL.
  * @error: Return location for error or %NULL.
  *
  * Registers an authentication agent.
@@ -280,6 +281,7 @@ polkit_backend_authority_register_authentication_agent (PolkitBackendAuthority
                                                         PolkitSubject             *subject,
                                                         const gchar               *locale,
                                                         const gchar               *object_path,
+                                                        GVariant                  *options,
                                                         GError                   **error)
 {
   PolkitBackendAuthorityClass *klass;
@@ -296,7 +298,7 @@ polkit_backend_authority_register_authentication_agent (PolkitBackendAuthority
     }
   else
     {
-      return klass->register_authentication_agent (authority, caller, subject, locale, object_path, error);
+      return klass->register_authentication_agent (authority, caller, subject, locale, object_path, options, error);
     }
 }
 
@@ -571,6 +573,12 @@ static const gchar *server_introspection_data =
   "      <arg type='s' name='locale' direction='in'/>"
   "      <arg type='s' name='object_path' direction='in'/>"
   "    </method>"
+  "    <method name='RegisterAuthenticationAgentWithOptions'>"
+  "      <arg type='(sa{sv})' name='subject' direction='in'/>"
+  "      <arg type='s' name='locale' direction='in'/>"
+  "      <arg type='s' name='object_path' direction='in'/>"
+  "      <arg type='a{sv}' name='options' direction='in'/>"
+  "    </method>"
   "    <method name='UnregisterAuthenticationAgent'>"
   "      <arg type='(sa{sv})' name='subject' direction='in'/>"
   "      <arg type='s' name='object_path' direction='in'/>"
@@ -873,6 +881,62 @@ server_handle_register_authentication_agent (Server                 *server,
                                                                subject,
                                                                locale,
                                                                object_path,
+                                                               NULL,
+                                                               &error))
+    {
+      g_dbus_method_invocation_return_gerror (invocation, error);
+      g_error_free (error);
+      goto out;
+    }
+
+  g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+
+ out:
+  if (subject != NULL)
+    g_object_unref (subject);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+server_handle_register_authentication_agent_with_options (Server                 *server,
+                                                          GVariant               *parameters,
+                                                          PolkitSubject          *caller,
+                                                          GDBusMethodInvocation  *invocation)
+{
+  GVariant *subject_gvariant;
+  GError *error;
+  PolkitSubject *subject;
+  const gchar *locale;
+  const gchar *object_path;
+  GVariant *options;
+
+  subject = NULL;
+
+  g_variant_get (parameters,
+                 "(@(sa{sv})&s&s at a{sv})",
+                 &subject_gvariant,
+                 &locale,
+                 &object_path,
+                 &options);
+
+  error = NULL;
+  subject = polkit_subject_new_for_gvariant (subject_gvariant, &error);
+  if (subject == NULL)
+    {
+      g_prefix_error (&error, "Error getting subject: ");
+      g_dbus_method_invocation_return_gerror (invocation, error);
+      g_error_free (error);
+      goto out;
+    }
+
+  error = NULL;
+  if (!polkit_backend_authority_register_authentication_agent (server->authority,
+                                                               caller,
+                                                               subject,
+                                                               locale,
+                                                               object_path,
+                                                               options,
                                                                &error))
     {
       g_dbus_method_invocation_return_gerror (invocation, error);
@@ -883,6 +947,8 @@ server_handle_register_authentication_agent (Server                 *server,
   g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
 
  out:
+  if (options != NULL)
+      g_variant_unref (options);
   if (subject != NULL)
     g_object_unref (subject);
 }
@@ -1150,6 +1216,8 @@ server_handle_method_call (GDBusConnection        *connection,
     server_handle_cancel_check_authorization (server, parameters, caller, invocation);
   else if (g_strcmp0 (method_name, "RegisterAuthenticationAgent") == 0)
     server_handle_register_authentication_agent (server, parameters, caller, invocation);
+  else if (g_strcmp0 (method_name, "RegisterAuthenticationAgentWithOptions") == 0)
+    server_handle_register_authentication_agent_with_options (server, parameters, caller, invocation);
   else if (g_strcmp0 (method_name, "UnregisterAuthenticationAgent") == 0)
     server_handle_unregister_authentication_agent (server, parameters, caller, invocation);
   else if (g_strcmp0 (method_name, "AuthenticationAgentResponse") == 0)
diff --git a/src/polkitbackend/polkitbackendauthority.h b/src/polkitbackend/polkitbackendauthority.h
index bfc0480..a564054 100644
--- a/src/polkitbackend/polkitbackendauthority.h
+++ b/src/polkitbackend/polkitbackendauthority.h
@@ -143,6 +143,7 @@ struct _PolkitBackendAuthorityClass
                                              PolkitSubject            *subject,
                                              const gchar              *locale,
                                              const gchar              *object_path,
+                                             GVariant                 *options,
                                              GError                  **error);
 
   gboolean (*unregister_authentication_agent) (PolkitBackendAuthority   *authority,
@@ -244,6 +245,7 @@ gboolean polkit_backend_authority_register_authentication_agent (PolkitBackendAu
                                                                  PolkitSubject             *subject,
                                                                  const gchar               *locale,
                                                                  const gchar               *object_path,
+                                                                 GVariant                  *options,
                                                                  GError                   **error);
 
 gboolean polkit_backend_authority_unregister_authentication_agent (PolkitBackendAuthority    *authority,
diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c
index f523782..b237e9d 100644
--- a/src/polkitbackend/polkitbackendinteractiveauthority.c
+++ b/src/polkitbackend/polkitbackendinteractiveauthority.c
@@ -156,6 +156,7 @@ static gboolean polkit_backend_interactive_authority_register_authentication_age
                                                                                     PolkitSubject            *subject,
                                                                                     const gchar              *locale,
                                                                                     const gchar              *object_path,
+                                                                                    GVariant                 *options,
                                                                                     GError                  **error);
 
 static gboolean polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBackendAuthority   *authority,
@@ -431,6 +432,7 @@ struct AuthenticationAgent
   PolkitSubject *scope;
 
   gchar *locale;
+  GVariant *registration_options;
   gchar *object_path;
   gchar *unique_system_bus_name;
 
@@ -1541,11 +1543,12 @@ authentication_agent_unref (AuthenticationAgent *agent)
     {
       if (agent->proxy != NULL)
         g_object_unref (agent->proxy);
-
       g_object_unref (agent->scope);
       g_free (agent->locale);
       g_free (agent->object_path);
       g_free (agent->unique_system_bus_name);
+      if (agent->registration_options != NULL)
+        g_variant_unref (agent->registration_options);
       g_free (agent);
     }
 }
@@ -1554,7 +1557,8 @@ static AuthenticationAgent *
 authentication_agent_new (PolkitSubject *scope,
                           const gchar *unique_system_bus_name,
                           const gchar *locale,
-                          const gchar *object_path)
+                          const gchar *object_path,
+                          GVariant    *registration_options)
 {
   AuthenticationAgent *agent;
   GError *error;
@@ -1566,6 +1570,7 @@ authentication_agent_new (PolkitSubject *scope,
   agent->object_path = g_strdup (object_path);
   agent->unique_system_bus_name = g_strdup (unique_system_bus_name);
   agent->locale = g_strdup (locale);
+  agent->registration_options = registration_options != NULL ? g_variant_ref (registration_options) : NULL;
 
   error = NULL;
   agent->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
@@ -1592,19 +1597,16 @@ get_authentication_agent_for_subject (PolkitBackendInteractiveAuthority *authori
                                       PolkitSubject *subject)
 {
   PolkitBackendInteractiveAuthorityPrivate *priv;
-  PolkitSubject *session_for_subject;
-  AuthenticationAgent *agent;
+  PolkitSubject *session_for_subject = NULL;
+  AuthenticationAgent *agent = NULL;
+  AuthenticationAgent *agent_fallback = NULL;
+  gboolean fallback = FALSE;
 
   priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
 
-  agent = NULL;
-  session_for_subject = NULL;
-
   agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, subject);
-  if (agent != NULL)
-    goto out;
 
-  if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
+  if (agent == NULL && POLKIT_IS_SYSTEM_BUS_NAME (subject))
     {
       PolkitSubject *process;
       process = polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (subject),
@@ -1613,15 +1615,27 @@ get_authentication_agent_for_subject (PolkitBackendInteractiveAuthority *authori
       if (process != NULL)
         {
           agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, process);
-          if (agent != NULL)
-            {
-              g_object_unref (process);
-              goto out;
-            }
           g_object_unref (process);
         }
     }
 
+  if (agent != NULL)
+    {
+      /* We have an agent! Now see if we should use this as a fallback only */
+      if (agent->registration_options != NULL &&
+          g_variant_lookup (agent->registration_options, "fallback", "b", &fallback) &&
+          fallback)
+        {
+          agent_fallback = agent;
+          agent = NULL;
+        }
+      else
+        {
+          /* Nope, use it */
+          goto out;
+        }
+    }
+
   /* Now, we should also cover the case where @subject is a
    * UnixProcess but the agent is a SystemBusName. However, this can't
    * happen because we only allow registering agents for UnixProcess
@@ -1636,6 +1650,10 @@ get_authentication_agent_for_subject (PolkitBackendInteractiveAuthority *authori
 
   agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, session_for_subject);
 
+  /* use fallback, if available */
+  if (agent == NULL && agent_fallback != NULL)
+    agent = agent_fallback;
+
  out:
   if (session_for_subject != NULL)
     g_object_unref (session_for_subject);
@@ -2194,6 +2212,7 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken
                                                                     PolkitSubject            *subject,
                                                                     const gchar              *locale,
                                                                     const gchar              *object_path,
+                                                                    GVariant                 *options,
                                                                     GError                  **error)
 {
   PolkitBackendInteractiveAuthority *interactive_authority;
@@ -2302,7 +2321,8 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken
   agent = authentication_agent_new (subject,
                                     polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
                                     locale,
-                                    object_path);
+                                    object_path,
+                                    options);
 
   g_hash_table_insert (priv->hash_scope_to_authentication_agent,
                        g_object_ref (subject),
diff --git a/src/programs/pkttyagent.c b/src/programs/pkttyagent.c
index 1c170f4..488ca8b 100644
--- a/src/programs/pkttyagent.c
+++ b/src/programs/pkttyagent.c
@@ -52,15 +52,18 @@ main (int argc, char *argv[])
 {
   gboolean opt_show_help = FALSE;
   gboolean opt_show_version = FALSE;
+  gboolean opt_fallback = FALSE;
   PolkitAuthority *authority = NULL;
   PolkitSubject *subject = NULL;
   gpointer local_agent_handle = NULL;
   PolkitAgentListener *listener = NULL;
+  GVariant *options = NULL;
   GError *error;
   GMainLoop *loop = NULL;
   guint n;
   guint ret = 126;
   gint notify_fd = -1;
+  GVariantBuilder builder;
 
   g_type_init ();
 
@@ -74,6 +77,10 @@ main (int argc, char *argv[])
         {
           opt_show_version = TRUE;
         }
+      else if (g_strcmp0 (argv[n], "--fallback") == 0)
+        {
+          opt_fallback = TRUE;
+        }
       else if (g_strcmp0 (argv[n], "--notify-fd") == 0)
         {
           n++;
@@ -180,6 +187,13 @@ main (int argc, char *argv[])
       goto out;
     }
 
+  if (opt_fallback)
+    {
+      g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+      g_variant_builder_add (&builder, "{sv}", "fallback", g_variant_new_boolean (TRUE));
+      options = g_variant_builder_end (&builder);
+    }
+
   error = NULL;
   /* this will fail if we can't find a controlling terminal */
   listener = polkit_agent_text_listener_new (NULL, &error);
@@ -191,12 +205,14 @@ main (int argc, char *argv[])
       ret = 127;
       goto out;
     }
-  local_agent_handle = polkit_agent_listener_register (listener,
-                                                       POLKIT_AGENT_REGISTER_FLAGS_RUN_IN_THREAD,
-                                                       subject,
-                                                       NULL, /* object_path */
-                                                       NULL, /* GCancellable */
-                                                       &error);
+  local_agent_handle = polkit_agent_listener_register_with_options (listener,
+                                                                    POLKIT_AGENT_REGISTER_FLAGS_RUN_IN_THREAD,
+                                                                    subject,
+                                                                    NULL, /* object_path */
+                                                                    options,
+                                                                    NULL, /* GCancellable */
+                                                                    &error);
+  options = NULL; /* consumed */
   g_object_unref (listener);
   if (local_agent_handle == NULL)
     {
@@ -225,6 +241,9 @@ main (int argc, char *argv[])
   if (local_agent_handle != NULL)
     polkit_agent_listener_unregister (local_agent_handle);
 
+  if (options != NULL)
+    g_variant_unref (options);
+
   if (subject != NULL)
     g_object_unref (subject);
 


More information about the hal-commit mailing list