PolicyKit: Branch 'master'

David Zeuthen david at kemper.freedesktop.org
Thu Dec 10 11:51:12 PST 2009


 configure.ac                                             |    4 
 docs/man/pklocalauthority.xml                            |  122 ++++++-
 src/polkitbackend/Makefile.am                            |    3 
 src/polkitbackend/polkitbackendlocalauthority.c          |  240 +++++++++++++--
 src/polkitbackend/polkitbackendlocalauthorizationstore.c |    6 
 5 files changed, 334 insertions(+), 41 deletions(-)

New commits:
commit 8e0b9b47d1fc1a4ab6020770e4b3084ddd45b71d
Author: David Zeuthen <davidz at redhat.com>
Date:   Thu Dec 10 14:45:10 2009 -0500

    Bug 25367 — Also read local authority configuration data from /etc
    
    Turns out some people would rather edit local files in /etc rather
    than shipping them in a package (as e.g. Fedora does with the
    polkit-desktop-policy RPM).
    
    This also drops the hard-coded list of directory names such as
    10-vendor.d, 20-org.d - we now monitor the
    /var/lib/polkit-1/localauthority and /etc/polkit-1/localauthority
    directories for changes - whenever we see a subdirectory in any of
    these directories, we create an AuthorizationStore object that looks
    for .pkla files.
    
    Signed-off-by: David Zeuthen <davidz at redhat.com>

diff --git a/configure.ac b/configure.ac
index 7d42ac0..2605187 100644
--- a/configure.ac
+++ b/configure.ac
@@ -484,6 +484,10 @@ echo "
 
 "
 
+echo "NOTE: The directory ${sysconfdir}/polkit-1/localauthority must be owned"
+echo "      by root and have mode 700"
+echo
+
 echo "NOTE: The directory ${localstatedir}/lib/polkit-1 must be owned"
 echo "      by root and have mode 700"
 echo
diff --git a/docs/man/pklocalauthority.xml b/docs/man/pklocalauthority.xml
index 5ba01a6..f0343f3 100644
--- a/docs/man/pklocalauthority.xml
+++ b/docs/man/pklocalauthority.xml
@@ -91,7 +91,22 @@
     <title>DIRECTORY STRUCTURE</title>
     <para>
       The Local Authority reads files with <filename>.pkla</filename>
-      extension from the following directories
+      extension from all directories located inside the
+      <filename>/etc/polkit-1/localauthority</filename>
+      and <filename>/var/lib/polkit-1/localauthority</filename>
+      directories. By default, the following sub-directories are installed.
+    </para>
+    <programlisting>
+/etc/polkit-1/
+`-- localauthority
+    |-- 10-vendor.d
+    |-- 20-org.d
+    |-- 30-site.d
+    |-- 50-local.d
+    `-- 90-mandatory.d
+    </programlisting>
+    <para>
+      and
     </para>
     <programlisting>
 /var/lib/polkit-1/
@@ -103,6 +118,12 @@
     `-- 90-mandatory.d
     </programlisting>
     <para>
+      The <filename>/etc/polkit-1/localauthority</filename> hierarchy
+      is inteded for local configuration and
+      the <filename>/var/lib/polkit-1/localauthority</filename> is
+      intended for 3rd party packages.
+    </para>
+    <para>
       Each <filename>.pkla</filename> file contains one or more
       authorization entries. If the underlying filesystem supports
       file monitoring, the Local Authority will reload information
@@ -117,7 +138,7 @@
         <term><emphasis>10-vendor.d</emphasis></term>
         <listitem>
           <para>
-            Reserved for the Operating System vendor.
+            Intended for use by the OS vendor.
           </para>
         </listitem>
       </varlistentry>
@@ -125,7 +146,7 @@
         <term><emphasis>20-org.d</emphasis></term>
         <listitem>
           <para>
-            Reserved for the organization deploying the system.
+            Intended for the organization deploying the OS.
           </para>
         </listitem>
       </varlistentry>
@@ -133,7 +154,7 @@
         <term><emphasis>30-site.d</emphasis></term>
         <listitem>
           <para>
-            Reserved for site deploying the system.
+            Intended for the site deploying the system.
           </para>
         </listitem>
       </varlistentry>
@@ -141,7 +162,7 @@
         <term><emphasis>50-local.d</emphasis></term>
         <listitem>
           <para>
-            Reserved for local usage.
+            Intended for local usage.
           </para>
         </listitem>
       </varlistentry>
@@ -149,15 +170,19 @@
         <term><emphasis>90-mandatory.d</emphasis></term>
         <listitem>
           <para>
-            Reserved for the organization deploying the system.
+            Intended for the organization deploying the OS.
           </para>
         </listitem>
       </varlistentry>
     </variablelist>
     <para>
-      Each <filename>.pkla</filename> file is a standard <emphasis>key
-      file</emphasis> and contains key/value pairs in one or more
-      groups with each group representing an authorization entry.
+      and new directories can be added/removed as needed.
+    </para>
+    <para>
+      As to regards to the content, each <filename>.pkla</filename>
+      file is a standard <emphasis>key file</emphasis> and contains
+      key/value pairs in one or more groups with each group
+      representing an authorization entry.
       A <filename>.pkla</filename> file MUST be named by using a
       scheme to ensure that the name is unique, e.g. reverse DNS
       notation or similar. For example, if the organization is
@@ -261,13 +286,78 @@
       following algorithm.
     </para>
     <para>
-      First, the user of the Subject is determined and the groups that
-      the user belongs are looked up. For each group identity, the
-      authorization entries are consulted in the lexigraphical order
-      (using standard lexicographical sorting (using the standard C
-      locale) of file names and appearance of each group in each
-      file). If the authorization check matches the data from the
-      authorization check, then the authorization result
+      The authorization entries from all .pkla files are ordered using
+      the following rules. First all the basename of all
+      sub-directories (e.g. <emphasis>30-site.d</emphasis>) from both
+      the <filename>/etc/polkit-1/localauthority</filename>
+      and <filename>/var/lib/polkit-1/localauthority</filename>
+      directories are enumerated and sorted (using the C locale). If a
+      name exists in both <filename>/etc</filename>
+      and <filename>/var</filename>, the one
+      in <filename>/etc</filename> takes precedence. Then
+      all <filename>.pkla</filename> files are read in order from this
+      list of sub-directories. For each <filename>.pkla</filename>
+      file, authorizations from each file are appended in order resulting
+      in an ordered list of authorization entries.
+    </para>
+    <para>
+      For example, given the following files
+    </para>
+    <programlisting>
+/var/lib/polkit-1
+└── localauthority
+    ├── 10-vendor.d
+    │   └── 10-desktop-policy.pkla
+    ├── 20-org.d
+    ├── 30-site.d
+    ├── 50-local.d
+    ├── 55-org.my.company.d
+    │   └── 10-org.my.company.product.pkla
+    └── 90-mandatory.d
+
+/etc/polkit-1
+└── localauthority
+    ├── 10-vendor.d
+    │   └── 01-some-changes-from-a-subvendor.pkla
+    ├── 20-org.d
+    ├── 30-site.d
+    ├── 50-local.d
+    ├── 55-org.my.company.d
+    │   └── 10-org.my.company.product.pkla
+    └── 90-mandatory.d
+    </programlisting>
+    <para>
+      the evaluation order of the <filename>.pkla</filename> files is:
+    </para>
+    <orderedlist>
+      <listitem>
+	<para>
+          <filename>10-desktop-policy.pkla</filename>
+        </para>
+      </listitem>
+      <listitem>
+	<para>
+          <filename>01-some-changes-from-a-subvendor.pkla</filename>
+        </para>
+      </listitem>
+      <listitem>
+	<para>
+          <filename>10-org.my.company.product.pkla</filename> (the <filename>/var</filename> one)
+        </para>
+      </listitem>
+      <listitem>
+	<para>
+          <filename>10-org.my.company.product.pkla</filename> (the <filename>/etc</filename> one)
+        </para>
+      </listitem>
+    </orderedlist>
+    <para>
+      When the list of authorization entries has been calculated, the
+      authorization check can be made. First, the user of the Subject
+      is determined and the groups that the user belongs are looked
+      up. For each group identity, the authorization entries are
+      consulted in order. If the authorization check matches the data
+      from the authorization check, then the authorization result
       from <emphasis>RequireAny</emphasis>, <emphasis>RequireInactive</emphasis>
       or <emphasis>RequireActive</emphasis> is used
       and <emphasis>ReturnValue</emphasis> is added to the
diff --git a/src/polkitbackend/Makefile.am b/src/polkitbackend/Makefile.am
index 48695d2..4cb7310 100644
--- a/src/polkitbackend/Makefile.am
+++ b/src/polkitbackend/Makefile.am
@@ -103,4 +103,7 @@ install-exec-hook:
 	mkdir -p $(DESTDIR)$(localstatedir)/lib/polkit-1
 	mkdir -p $(DESTDIR)$(localstatedir)/lib/polkit-1/localauthority/{10-vendor.d,20-org.d,30-site.d,50-local.d,90-mandatory.d}
 	-chmod 700 $(DESTDIR)$(localstatedir)/lib/polkit-1
+	mkdir -p $(DESTDIR)$(sysconfdir)/polkit-1
+	mkdir -p $(DESTDIR)$(sysconfdir)/polkit-1/localauthority/{10-vendor.d,20-org.d,30-site.d,50-local.d,90-mandatory.d}
+	-chmod 700 $(DESTDIR)$(sysconfdir)/polkit-1/localauthority
 	mkdir -p $(DESTDIR)$(libdir)/polkit-1/extensions
diff --git a/src/polkitbackend/polkitbackendlocalauthority.c b/src/polkitbackend/polkitbackendlocalauthority.c
index 3672f4c..737b7d2 100644
--- a/src/polkitbackend/polkitbackendlocalauthority.c
+++ b/src/polkitbackend/polkitbackendlocalauthority.c
@@ -66,6 +66,9 @@ typedef struct
 
   GList *authorization_stores;
 
+  GFileMonitor *sysconf_dir_monitor;
+  GFileMonitor *localstate_dir_monitor;
+
 } PolkitBackendLocalAuthorityPrivate;
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -131,43 +134,226 @@ on_store_changed (PolkitBackendLocalAuthorizationStore *store,
   g_signal_emit_by_name (authority, "changed");
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
-polkit_backend_local_authority_init (PolkitBackendLocalAuthority *authority)
+purge_all_authorization_stores (PolkitBackendLocalAuthority *authority)
 {
   PolkitBackendLocalAuthorityPrivate *priv;
-  GFile *directory;
+  GList *l;
+
+  priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (authority);
+
+  for (l = priv->authorization_stores; l != NULL; l = l->next)
+    {
+      PolkitBackendLocalAuthorizationStore *store = POLKIT_BACKEND_LOCAL_AUTHORIZATION_STORE (l->data);
+      g_signal_handlers_disconnect_by_func (store,
+                                            G_CALLBACK (on_store_changed),
+                                            authority);
+      g_object_unref (store);
+    }
+  g_list_free (priv->authorization_stores);
+  priv->authorization_stores = NULL;
+
+  g_debug ("Purged all local authorization stores");
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+add_one_authorization_store (PolkitBackendLocalAuthority *authority,
+                             GFile                       *directory)
+{
+  PolkitBackendLocalAuthorizationStore *store;
+  PolkitBackendLocalAuthorityPrivate *priv;
+
+  priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (authority);
+
+  store = polkit_backend_local_authorization_store_new (directory, ".pkla");
+  priv->authorization_stores = g_list_append (priv->authorization_stores, store);
+
+  g_signal_connect (store,
+                    "changed",
+                    G_CALLBACK (on_store_changed),
+                    authority);
+}
+
+static gint
+authorization_store_path_compare_func (GFile *file_a,
+                                       GFile *file_b)
+{
+  const gchar *a;
+  const gchar *b;
+
+  a = g_object_get_data (G_OBJECT (file_a), "sort-key");
+  b = g_object_get_data (G_OBJECT (file_b), "sort-key");
+
+  return g_strcmp0 (a, b);
+}
+
+static void
+add_all_authorization_stores (PolkitBackendLocalAuthority *authority)
+{
   guint n;
-  const gchar *store_locations[] =
+  GList *directories;
+  GList *l;
+
+  directories = NULL;
+
+  for (n = 0; n < 2; n++)
+    {
+      const gchar *toplevel_path;
+      GFile *toplevel_directory;
+      GFileEnumerator *directory_enumerator;
+      GFileInfo *file_info;
+      GError *error;
+
+      error = NULL;
+
+      if (n == 0)
+        toplevel_path = PACKAGE_LOCALSTATE_DIR "/lib/polkit-1/localauthority";
+      else
+        toplevel_path = PACKAGE_SYSCONF_DIR "/polkit-1/localauthority";
+
+      toplevel_directory = g_file_new_for_path (toplevel_path);
+      directory_enumerator = g_file_enumerate_children (toplevel_directory,
+                                                        "standard::*",
+                                                        G_FILE_QUERY_INFO_NONE,
+                                                        NULL,
+                                                        &error);
+      if (directory_enumerator == NULL)
+        {
+          g_warning ("Error getting enumerator for %s: %s", toplevel_path, error->message);
+          g_error_free (error);
+          g_object_unref (toplevel_directory);
+          continue;
+        }
+
+      while ((file_info = g_file_enumerator_next_file (directory_enumerator, NULL, &error)) != NULL)
+        {
+          /* only consider directories */
+          if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
+            {
+              const gchar *name;
+              GFile *directory;
+              gchar *sort_key;
+
+              name = g_file_info_get_name (file_info);
+
+              /* This makes entries in directories in /etc take precedence to entries in directories in /var */
+              sort_key = g_strdup_printf ("%s-%d", name, n);
+
+              directory = g_file_get_child (toplevel_directory, name);
+              g_object_set_data_full (G_OBJECT (directory), "sort-key", sort_key, g_free);
+
+              directories = g_list_prepend (directories, directory);
+            }
+          g_object_unref (file_info);
+        }
+      if (error != NULL)
+        {
+          g_warning ("Error enumerating files in %s: %s", toplevel_path, error->message);
+          g_error_free (error);
+          g_object_unref (toplevel_directory);
+          g_object_unref (directory_enumerator);
+          continue;
+        }
+      g_object_unref (directory_enumerator);
+      g_object_unref (toplevel_directory);
+    }
+
+  /* Sort directories */
+  directories = g_list_sort (directories, (GCompareFunc) authorization_store_path_compare_func);
+
+  /* And now add an authorization store for each one */
+  for (l = directories; l != NULL; l = l->next)
     {
-      PACKAGE_LOCALSTATE_DIR "/lib/polkit-1/localauthority/10-vendor.d",
-      PACKAGE_LOCALSTATE_DIR "/lib/polkit-1/localauthority/20-org.d",
-      PACKAGE_LOCALSTATE_DIR "/lib/polkit-1/localauthority/30-site.d",
-      PACKAGE_LOCALSTATE_DIR "/lib/polkit-1/localauthority/50-local.d",
-      PACKAGE_LOCALSTATE_DIR "/lib/polkit-1/localauthority/90-mandatory.d",
-      NULL
-    };
+      GFile *directory = G_FILE (l->data);
+      gchar *name;
+
+      name = g_file_get_path (directory);
+      g_debug ("Added `%s' as a local authorization store", name);
+      g_free (name);
+
+      add_one_authorization_store (authority, directory);
+    }
+
+  g_list_foreach (directories, (GFunc) g_object_unref, NULL);
+  g_list_free (directories);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_toplevel_authority_store_monitor_changed (GFileMonitor     *monitor,
+                                             GFile            *file,
+                                             GFile            *other_file,
+                                             GFileMonitorEvent event_type,
+                                             gpointer          user_data)
+{
+  PolkitBackendLocalAuthority *authority = POLKIT_BACKEND_LOCAL_AUTHORITY (user_data);
+
+  purge_all_authorization_stores (authority);
+  add_all_authorization_stores (authority);
+}
+
+static void
+polkit_backend_local_authority_init (PolkitBackendLocalAuthority *authority)
+{
+  PolkitBackendLocalAuthorityPrivate *priv;
+  GFile *config_directory;
+  guint n;
 
   priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (authority);
 
-  directory = g_file_new_for_path (PACKAGE_SYSCONF_DIR "/polkit-1/localauthority.conf.d");
-  priv->config_source = polkit_backend_config_source_new (directory);
-  g_object_unref (directory);
+  config_directory = g_file_new_for_path (PACKAGE_SYSCONF_DIR "/polkit-1/localauthority.conf.d");
+  priv->config_source = polkit_backend_config_source_new (config_directory);
+  g_object_unref (config_directory);
 
-  for (n = 0; store_locations[n] != NULL; n++)
+  add_all_authorization_stores (authority);
+
+  /* Monitor the toplevels */
+  for (n = 0; n < 2; n++)
     {
-      PolkitBackendLocalAuthorizationStore *store;
+      const gchar *toplevel_path;
+      GFile *toplevel_directory;
+      GFileMonitor *monitor;
+      GError *error;
+
+      if (n == 0)
+        toplevel_path = PACKAGE_LOCALSTATE_DIR "/lib/polkit-1/localauthority";
+      else
+        toplevel_path = PACKAGE_SYSCONF_DIR "/polkit-1/localauthority";
+
+      toplevel_directory = g_file_new_for_path (toplevel_path);
+
+      error = NULL;
+      monitor = g_file_monitor_directory (toplevel_directory,
+                                          G_FILE_MONITOR_NONE,
+                                          NULL,
+                                          &error);
+      if (monitor == NULL)
+        {
+          g_warning ("Error creating file monitor for %s: %s", toplevel_path, error->message);
+          g_error_free (error);
+          g_object_unref (toplevel_directory);
+          continue;
+        }
 
-      directory = g_file_new_for_path (store_locations[n]);
-      store = polkit_backend_local_authorization_store_new (directory, ".pkla");
-      priv->authorization_stores = g_list_prepend (priv->authorization_stores, store);
-      g_object_unref (directory);
+      g_debug ("Monitoring `%s' for changes", toplevel_path);
 
-      g_signal_connect (store,
+      g_signal_connect (monitor,
                         "changed",
-                        G_CALLBACK (on_store_changed),
+                        G_CALLBACK (on_toplevel_authority_store_monitor_changed),
                         authority);
+
+      if (n == 0)
+        priv->sysconf_dir_monitor = monitor;
+      else
+        priv->localstate_dir_monitor = monitor;
+
+      g_object_unref (toplevel_directory);
     }
-  priv->authorization_stores = g_list_reverse (priv->authorization_stores);
 }
 
 static void
@@ -179,12 +365,16 @@ polkit_backend_local_authority_finalize (GObject *object)
   local_authority = POLKIT_BACKEND_LOCAL_AUTHORITY (object);
   priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (local_authority);
 
+  purge_all_authorization_stores (local_authority);
+
+  if (priv->sysconf_dir_monitor != NULL)
+    g_object_unref (priv->sysconf_dir_monitor);
+  if (priv->localstate_dir_monitor != NULL)
+    g_object_unref (priv->localstate_dir_monitor);
+
   if (priv->config_source != NULL)
     g_object_unref (priv->config_source);
 
-  g_list_foreach (priv->authorization_stores, (GFunc) g_object_unref, NULL);
-  g_list_free (priv->authorization_stores);
-
   G_OBJECT_CLASS (polkit_backend_local_authority_parent_class)->finalize (object);
 }
 
diff --git a/src/polkitbackend/polkitbackendlocalauthorizationstore.c b/src/polkitbackend/polkitbackendlocalauthorizationstore.c
index bdd0103..5d5dc14 100644
--- a/src/polkitbackend/polkitbackendlocalauthorizationstore.c
+++ b/src/polkitbackend/polkitbackendlocalauthorizationstore.c
@@ -518,6 +518,12 @@ polkit_backend_local_authorization_store_new (GFile       *directory,
 static void
 polkit_backend_local_authorization_store_purge (PolkitBackendLocalAuthorizationStore *store)
 {
+  gchar *path;
+
+  path = g_file_get_path (store->priv->directory);
+  g_debug ("Dropping all .pkla caches for directory `%s'", path);
+  g_free (path);
+
   g_list_foreach (store->priv->authorizations, (GFunc) local_authorization_free, NULL);
   g_list_free (store->priv->authorizations);
   store->priv->authorizations = NULL;


More information about the hal-commit mailing list