PolicyKit: Branch 'master'

David Zeuthen david at kemper.freedesktop.org
Tue Sep 20 11:17:33 PDT 2011


 docs/man/polkit.xml                                   |   25 ++++++
 src/polkitbackend/polkitbackendinteractiveauthority.c |   67 ++++++++++++++++++
 2 files changed, 90 insertions(+), 2 deletions(-)

New commits:
commit 6bbd5189e967e8ddc36100bf22cd12bcb152ab5f
Author: David Zeuthen <davidz at redhat.com>
Date:   Tue Sep 20 14:13:12 2011 -0400

    Add support for the org.freedesktop.policykit.imply annotation
    
    For example, GNOME control center can now defined e.g.
    
      <action id="org.zee.example.meta">
        <description>Meta Action</description>
        <message>Example of a meta action, blabla</message>
        <defaults>
          <allow_any>no</allow_any>
          <allow_inactive>no</allow_inactive>
          <allow_active>auth_admin_keep</allow_active>
        </defaults>
        <annotate key="org.freedesktop.policykit.imply">org.freedesktop.udisks2.ata-smart-selftest org.freedesktop.udisks2.encrypted-lock-others org.freedesktop.udisks2.filesystem-unmount-others</annotate>
      </action>
    
    and set up a single GtkLockButton for a PolkitPermission for action id
    "org.zee.example.meta".
    
    When unlocked the given subject will now be authorized for the actions
    mentioned in the annotation.
    
    Example test program:
    
    int
    main (int argc, char *argv[])
    {
      PolkitSubject *subject;
      GtkWidget *window;
      GtkWidget *table;
      GMainLoop *loop;
      guint n;
    
      gtk_init (&argc, &argv);
    
      subject = polkit_unix_process_new (getpid ());
    
      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    
      table = gtk_table_new (1, 2, FALSE);
      for (n = 1; n < argc; n++)
        {
          const gchar *action_id = argv[n];
          GPermission *permission;
          GtkWidget *label;
          GtkWidget *lock_button;
          GError *error = NULL;
    
          label = gtk_label_new (action_id);
    
          permission = polkit_permission_new_sync (action_id, subject, NULL, &error);
          if (permission == NULL)
            {
              g_error ("Error constructing permission for action_id %s: %s (%s, %d)",
                       action_id, error->message, g_quark_to_string (error->domain), error->code);
              goto out;
            }
          lock_button = gtk_lock_button_new (permission);
          g_object_unref (permission);
    
          gtk_table_attach (GTK_TABLE (table), label,       0, 1, n - 1, n, GTK_FILL, GTK_FILL, 0, 0);
          gtk_table_attach (GTK_TABLE (table), lock_button, 1, 2, n - 1, n, GTK_FILL, GTK_FILL, 0, 0);
        }
      gtk_container_add (GTK_CONTAINER (window), table);
    
      gtk_widget_show_all (window);
    
      loop = g_main_loop_new (NULL, FALSE);
      g_main_loop_run (loop);
    
     out:
      ;
    }
    
    Compile with:
    
     gcc -o showpolkit showpolkit.c `pkg-config --cflags --libs polkit-gobject-1 gtk+-3.0` -g -O0
    
    Run with:
    
     ./showpolkit org.freedesktop.udisks2.ata-smart-selftest org.freedesktop.udisks2.encrypted-lock-others org.freedesktop.udisks2.filesystem-unmount-others org.zee.example.meta
    
    Signed-off-by: David Zeuthen <davidz at redhat.com>

diff --git a/docs/man/polkit.xml b/docs/man/polkit.xml
index bcb276b..bfa5ccd 100644
--- a/docs/man/polkit.xml
+++ b/docs/man/polkit.xml
@@ -369,8 +369,7 @@ System Context         |                        |
         the <literal>key</literal> attribute and the value is
         specified using the <literal>value</literal> attribute. This
         element may appear zero or more times. See
-            <citerefentry><refentrytitle>pkexec</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-            for an example of how this can be used. </para></listitem>
+            below for known annotations. </para></listitem>
       </varlistentry>
       <varlistentry>
         <term><emphasis>vendor</emphasis></term>
@@ -398,6 +397,28 @@ System Context         |                        |
       <citerefentry><refentrytitle>pkaction</refentrytitle><manvolnum>1</manvolnum></citerefentry>
       command.
     </para>
+
+    <refsect2><title>Known annotations</title>
+    <para>
+      The <literal>org.freedesktop.policykit.exec.path</literal>
+      annotation is used by the <command>pkexec</command> program
+      shipped with PolicyKit - see the
+      <citerefentry><refentrytitle>pkexec</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      man page for details.
+    </para>
+    <para>
+      The <literal>org.freedesktop.policykit.imply</literal>
+      annotation (its value is a string containing a space separated
+      list of action identifiers) can be used to define <emphasis>meta
+      actions</emphasis>. The way it works is that if a subject is
+      authorized for an action with this annotation, then it is also
+      authorized for any action specified by the annotation. A typical
+      use of this annotation is when defining an UI shell with a
+      single lock button that should unlock multiple actions from
+      distinct mechanisms.
+    </para>
+    </refsect2>
+
   </refsect1>
 
   <refsect1 id="polkit-author"><title>AUTHOR</title>
diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c
index 8b32459..3566248 100644
--- a/src/polkitbackend/polkitbackendinteractiveauthority.c
+++ b/src/polkitbackend/polkitbackendinteractiveauthority.c
@@ -148,6 +148,7 @@ static PolkitAuthorizationResult *check_authorization_sync (PolkitBackendAuthori
                                                             PolkitDetails                  *details,
                                                             PolkitCheckAuthorizationFlags   flags,
                                                             PolkitImplicitAuthorization    *out_implicit_authorization,
+                                                            gboolean                        checking_imply,
                                                             GError                        **error);
 
 static gboolean polkit_backend_interactive_authority_register_authentication_agent (PolkitBackendAuthority   *authority,
@@ -890,6 +891,7 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority
                                      details,
                                      flags,
                                      &implicit_authorization,
+                                     FALSE, /* checking_imply */
                                      &error);
   if (error != NULL)
     {
@@ -964,6 +966,7 @@ check_authorization_sync (PolkitBackendAuthority         *authority,
                           PolkitDetails                  *details,
                           PolkitCheckAuthorizationFlags   flags,
                           PolkitImplicitAuthorization    *out_implicit_authorization,
+                          gboolean                        checking_imply,
                           GError                        **error)
 {
   PolkitBackendInteractiveAuthority *interactive_authority;
@@ -979,12 +982,15 @@ check_authorization_sync (PolkitBackendAuthority         *authority,
   PolkitImplicitAuthorization implicit_authorization;
   const gchar *tmp_authz_id;
   PolkitDetails *result_details;
+  GList *actions;
+  GList *l;
 
   interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
   priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
 
   result = NULL;
 
+  actions = NULL;
   user_of_subject = NULL;
   groups_of_user = NULL;
   subject_str = NULL;
@@ -1095,6 +1101,64 @@ check_authorization_sync (PolkitBackendAuthority         *authority,
       goto out;
     }
 
+  /* then see if implied by another action that the subject is authorized for
+   * (but only one level deep to avoid infinite recursion)
+   *
+   * TODO: if this is slow, we can maintain a hash table for looking up what
+   * actions implies a given action
+   */
+  if (!checking_imply)
+    {
+      actions = polkit_backend_action_pool_get_all_actions (priv->action_pool, NULL);
+      for (l = actions; l != NULL; l = l->next)
+        {
+          PolkitActionDescription *imply_ad = POLKIT_ACTION_DESCRIPTION (l->data);
+          const gchar *imply;
+          imply = polkit_action_description_get_annotation (imply_ad, "org.freedesktop.policykit.imply");
+          if (imply != NULL)
+            {
+              gchar **tokens;
+              guint n;
+              tokens = g_strsplit (imply, " ", 0);
+              for (n = 0; tokens[n] != NULL; n++)
+                {
+                  if (g_strcmp0 (tokens[n], action_id) == 0)
+                    {
+                      PolkitAuthorizationResult *implied_result = NULL;
+                      PolkitImplicitAuthorization implied_implicit_authorization;
+                      GError *implied_error = NULL;
+                      const gchar *imply_action_id;
+
+                      imply_action_id = polkit_action_description_get_action_id (imply_ad);
+
+                      /* g_debug ("%s is implied by %s, checking", action_id, imply_action_id); */
+                      implied_result = check_authorization_sync (authority, caller, subject,
+                                                                 imply_action_id,
+                                                                 details, flags,
+                                                                 &implied_implicit_authorization, TRUE,
+                                                                 &implied_error);
+                      if (implied_result != NULL)
+                        {
+                          if (polkit_authorization_result_get_is_authorized (implied_result))
+                            {
+                              g_debug (" is authorized (implied by %s)", imply_action_id);
+                              result = implied_result;
+                              /* cleanup */
+                              g_object_unref (result_details);
+                              g_strfreev (tokens);
+                              goto out;
+                            }
+                          g_object_unref (implied_result);
+                        }
+                      if (implied_error != NULL)
+                        g_error_free (implied_error);
+                    }
+                }
+              g_strfreev (tokens);
+            }
+        }
+    }
+
   if (implicit_authorization != POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED)
     {
       if (implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_AUTHENTICATION_REQUIRED_RETAINED ||
@@ -1118,6 +1182,9 @@ check_authorization_sync (PolkitBackendAuthority         *authority,
       g_debug (" not authorized");
     }
  out:
+  g_list_foreach (actions, (GFunc) g_object_unref, NULL);
+  g_list_free (actions);
+
   g_free (subject_str);
 
   g_list_foreach (groups_of_user, (GFunc) g_object_unref, NULL);


More information about the hal-commit mailing list