summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2009-02-09 21:10:46 -0500
committerDavid Zeuthen <davidz@redhat.com>2009-02-09 21:10:46 -0500
commit2d65587fbf21bcaacce05798533ffd0900e132d9 (patch)
treef8655fa32563cf421a8c9fea185d82a78057e4bd
parentd288deca00eba5a2ac24a0b852af4270a3d8c79c (diff)
make it possible to define what administrator authentication means0.91
We might also want to expose methods on the D-Bus interface org.freedesktop.PolicyKit1.AuthorityManager to configure this; implementation-wise we'd just be writing out config files with a fixed priority.
-rw-r--r--docs/TODO4
-rw-r--r--docs/polkit/polkit-docs.xml1
-rw-r--r--docs/polkitbackend/polkitbackend-sections.txt19
-rw-r--r--docs/polkitbackend/polkitbackend.types1
-rw-r--r--src/nullbackend/50-nullbackend.conf13
-rw-r--r--src/nullbackend/polkitbackendnullauthority.c122
-rw-r--r--src/polkitbackend/50-localauthority.conf26
-rw-r--r--src/polkitbackend/Makefile.am6
-rw-r--r--src/polkitbackend/polkitbackend.h1
-rw-r--r--src/polkitbackend/polkitbackendconfigsource.c563
-rw-r--r--src/polkitbackend/polkitbackendconfigsource.h97
-rw-r--r--src/polkitbackend/polkitbackendlocalauthority.c149
-rw-r--r--src/polkitbackend/polkitbackendtypes.h2
13 files changed, 868 insertions, 136 deletions
diff --git a/docs/TODO b/docs/TODO
index 36c1eec..2230711 100644
--- a/docs/TODO
+++ b/docs/TODO
@@ -22,10 +22,6 @@ Core TODO items
- make sure simple operations work when no system bus is present
- e.g. %post RPM scripts adding/removing authorizations to identities
- - for administrator authentication, make it possible to use 'wheel' group
- sudo-style authentication (e.g. select one or more identities that the
- user can choose to authenticate as)
-
- maybe use file monitors on /var/lib/polkit-1 directories and
emit the Changed() signal
diff --git a/docs/polkit/polkit-docs.xml b/docs/polkit/polkit-docs.xml
index 5cdb817..75e7620 100644
--- a/docs/polkit/polkit-docs.xml
+++ b/docs/polkit/polkit-docs.xml
@@ -90,6 +90,7 @@
<xi:include href="../polkitbackend/xml/polkitbackendlocalauthority.xml"/>
<xi:include href="../polkitbackend/xml/polkitbackendactionpool.xml"/>
<xi:include href="../polkitbackend/xml/polkitbackendsessionmonitor.xml"/>
+ <xi:include href="../polkitbackend/xml/polkitbackendconfigsource.xml"/>
</reference>
<reference id="ref-authentication-agent-api">
diff --git a/docs/polkitbackend/polkitbackend-sections.txt b/docs/polkitbackend/polkitbackend-sections.txt
index 1c8f925..e370b96 100644
--- a/docs/polkitbackend/polkitbackend-sections.txt
+++ b/docs/polkitbackend/polkitbackend-sections.txt
@@ -81,3 +81,22 @@ POLKIT_BACKEND_SESSION_MONITOR_CLASS
POLKIT_BACKEND_IS_SESSION_MONITOR_CLASS
POLKIT_BACKEND_SESSION_MONITOR_GET_CLASS
</SECTION>
+
+<SECTION>
+<FILE>polkitbackendconfigsource</FILE>
+PolkitBackendConfigSource
+polkit_backend_config_source_new
+polkit_backend_config_source_get_integer
+polkit_backend_config_source_get_boolean
+polkit_backend_config_source_get_double
+polkit_backend_config_source_get_string
+polkit_backend_config_source_get_string_list
+<SUBSECTION Standard>
+POLKIT_BACKEND_CONFIG_SOURCE
+POLKIT_BACKEND_IS_CONFIG_SOURCE
+POLKIT_BACKEND_TYPE_CONFIG_SOURCE
+polkit_backend_config_source_get_type
+POLKIT_BACKEND_CONFIG_SOURCE_CLASS
+POLKIT_BACKEND_IS_CONFIG_SOURCE_CLASS
+POLKIT_BACKEND_CONFIG_SOURCE_GET_CLASS
+</SECTION>
diff --git a/docs/polkitbackend/polkitbackend.types b/docs/polkitbackend/polkitbackend.types
index 9b16c54..248f48b 100644
--- a/docs/polkitbackend/polkitbackend.types
+++ b/docs/polkitbackend/polkitbackend.types
@@ -2,3 +2,4 @@ polkit_backend_authority_get_type
polkit_backend_local_authority_get_type
polkit_backend_action_pool_get_type
polkit_backend_session_monitor_get_type
+polkit_backend_config_source_get_type
diff --git a/src/nullbackend/50-nullbackend.conf b/src/nullbackend/50-nullbackend.conf
index 1c91137..3497677 100644
--- a/src/nullbackend/50-nullbackend.conf
+++ b/src/nullbackend/50-nullbackend.conf
@@ -1,15 +1,16 @@
#
# Configuration file for the PolicyKit null backend.
#
-# Do not edit this file, it will be overwritten on update.
+# DO NOT EDIT THIS FILE, it will be overwritten on update.
#
# To change configuration, create another file in this directory with
-# a filename that is sorted after the 50-nullback.conf.
+# a filename that is sorted after the 50-nullback.conf and make
+# sure it has the .conf extension.
#
-# Only a single configuration item is supported now. The priority of
-# the null backend. It defaults to -10. See the PolicyKit documentation
-# for more information about PolicyKit backends.
+# Only a single configuration item, Priority, is supported.
+#
+# See the PolicyKit documentation for more information about PolicyKit.
#
[Configuration]
-priority=-10
+Priority=-10
diff --git a/src/nullbackend/polkitbackendnullauthority.c b/src/nullbackend/polkitbackendnullauthority.c
index 543d2cd..f754bd5 100644
--- a/src/nullbackend/polkitbackendnullauthority.c
+++ b/src/nullbackend/polkitbackendnullauthority.c
@@ -94,126 +94,17 @@ polkit_backend_null_authority_class_finalize (PolkitBackendNullAuthorityClass *k
{
}
-static gint
-compare_filename (GFile *a, GFile *b)
-{
- gchar *a_uri;
- gchar *b_uri;
- gint ret;
-
- a_uri = g_file_get_uri (a);
- b_uri = g_file_get_uri (b);
-
- ret = g_strcmp0 (a_uri, b_uri);
-
- return ret;
-}
-
-/* Loads and process all .conf files in /etc/polkit-1/nullbackend.conf.d/ in order */
-static void
-load_config (gint *out_priority)
-{
- GFileEnumerator *enumerator;
- GFile *directory;
- GFileInfo *file_info;
- GError *error;
- GList *files;
- GList *l;
-
- directory = g_file_new_for_path (PACKAGE_SYSCONF_DIR "/polkit-1/nullbackend.conf.d");
-
- files = NULL;
-
- error = NULL;
- enumerator = g_file_enumerate_children (directory,
- "standard::*",
- G_FILE_QUERY_INFO_NONE,
- NULL,
- &error);
- if (error != NULL)
- {
- g_warning ("Error enumerating files: %s", error->message);
- goto out;
- }
-
- while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL)
- {
- const gchar *name;
-
- name = g_file_info_get_name (file_info);
-
- /* only consider files ending in .conf */
- if (g_str_has_suffix (name, ".conf"))
- files = g_list_prepend (files, g_file_get_child (directory, name));
-
- g_object_unref (file_info);
- }
- if (error != NULL)
- {
- g_warning ("Error enumerating files: %s", error->message);
- goto out;
- }
- g_object_unref (enumerator);
-
- files = g_list_sort (files, (GCompareFunc) compare_filename);
-
- for (l = files; l != NULL; l = l->next)
- {
- GFile *file = G_FILE (l->data);
- gchar *filename;
- GKeyFile *key_file;
-
- filename = g_file_get_path (file);
-
- key_file = g_key_file_new ();
- error = NULL;
- if (!g_key_file_load_from_file (key_file,
- filename,
- G_KEY_FILE_NONE,
- NULL))
- {
- g_warning ("Error loading file %s: %s", filename, error->message);
- g_error_free (error);
- error = NULL;
- }
- else
- {
- gint priority;
-
- priority = g_key_file_get_integer (key_file,
- "Configuration",
- "priority",
- &error);
- if (error != NULL)
- {
- /* don't warn, not all config files may have this key */
- g_error_free (error);
- }
- else
- {
- *out_priority = priority;
- }
-
- g_key_file_free (key_file);
- }
-
- g_free (filename);
- }
-
- out:
- g_object_unref (directory);
- g_list_foreach (files, (GFunc) g_object_unref, NULL);
- g_list_free (files);
-}
-
void
polkit_backend_null_authority_register (GIOModule *module)
{
gint priority;
+ GFile *directory;
+ PolkitBackendConfigSource *source;
- priority = -1;
+ directory = g_file_new_for_path (PACKAGE_SYSCONF_DIR "/polkit-1/nullbackend.conf.d");
+ source = polkit_backend_config_source_new (directory);
- load_config (&priority);
+ priority = polkit_backend_config_source_get_integer (source, "Configuration", "Priority", NULL);
polkit_backend_null_authority_register_type (G_TYPE_MODULE (module));
@@ -223,6 +114,9 @@ polkit_backend_null_authority_register (GIOModule *module)
POLKIT_BACKEND_TYPE_NULL_AUTHORITY,
"null backend " PACKAGE_VERSION,
priority);
+
+ g_object_unref (directory);
+ g_object_unref (source);
}
/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/polkitbackend/50-localauthority.conf b/src/polkitbackend/50-localauthority.conf
new file mode 100644
index 0000000..4514828
--- /dev/null
+++ b/src/polkitbackend/50-localauthority.conf
@@ -0,0 +1,26 @@
+#
+# Configuration file for the PolicyKit local authority backend.
+#
+# DO NOT EDIT THIS FILE, it will be overwritten on update.
+#
+# To change configuration, create another file in this directory with
+# a filename that is sorted after the 50-localauthority.conf and make
+# sure it has the .conf extension.
+#
+# Only a single configuration item, AdminIdentities, is supported. It
+# specifies what set of identities to use for administrator authentication.
+# The value is a semicolon-separated list of identities. An identity can
+# be specified as
+#
+# unix-user:<user>
+# unix-group:<group>
+#
+# where <user> is username/uid and <group> is a groupname/gid. When
+# using the group directive, any user in the given group can chosen
+# for authentication.
+#
+# See the PolicyKit documentation for more information about PolicyKit.
+#
+
+[Configuration]
+AdminIdentities=unix-user:0
diff --git a/src/polkitbackend/Makefile.am b/src/polkitbackend/Makefile.am
index 4714856..51ebe3c 100644
--- a/src/polkitbackend/Makefile.am
+++ b/src/polkitbackend/Makefile.am
@@ -42,6 +42,7 @@ libpolkit_backend_1include_HEADERS = \
polkitbackendlocalauthority.h \
polkitbackendactionpool.h \
polkitbackendsessionmonitor.h \
+ polkitbackendconfigsource.h \
$(NULL)
libpolkit_backend_1_la_SOURCES = \
@@ -54,6 +55,7 @@ libpolkit_backend_1_la_SOURCES = \
polkitbackendlocalauthority.h polkitbackendlocalauthority.c \
polkitbackendactionpool.h polkitbackendactionpool.c \
polkitbackendsessionmonitor.h polkitbackendsessionmonitor.c \
+ polkitbackendconfigsource.h polkitbackendconfigsource.c \
$(NULL)
libpolkit_backend_1_la_CFLAGS = \
@@ -72,8 +74,12 @@ libpolkit_backend_1_la_LIBADD = \
CLEANFILES = $(BUILT_SOURCES)
+localauthorityconfigdir = $(sysconfdir)/polkit-1/localauthority.conf.d
+localauthorityconfig_DATA = 50-localauthority.conf
+
EXTRA_DIST = \
org.freedesktop.ConsoleKit.xml \
+ $(localauthorityconfig_DATA) \
$(NULL)
dist-hook :
diff --git a/src/polkitbackend/polkitbackend.h b/src/polkitbackend/polkitbackend.h
index b6dcc1d..57a9842 100644
--- a/src/polkitbackend/polkitbackend.h
+++ b/src/polkitbackend/polkitbackend.h
@@ -34,6 +34,7 @@
#include <polkitbackend/polkitbackendlocalauthority.h>
#include <polkitbackend/polkitbackendactionpool.h>
#include <polkitbackend/polkitbackendsessionmonitor.h>
+#include <polkitbackend/polkitbackendconfigsource.h>
#undef _POLKIT_BACKEND_INSIDE_POLKIT_BACKEND_H
#endif /* __POLKIT_BACKEND_H */
diff --git a/src/polkitbackend/polkitbackendconfigsource.c b/src/polkitbackend/polkitbackendconfigsource.c
new file mode 100644
index 0000000..348b3e1
--- /dev/null
+++ b/src/polkitbackend/polkitbackendconfigsource.c
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ */
+
+#include "config.h"
+
+#include <polkit/polkit.h>
+#include "polkitbackendconfigsource.h"
+
+/**
+ * SECTION:polkitbackendconfigsource
+ * @title: PolkitBackendConfigSource
+ * @short_description: Access configuration files
+ *
+ * The #PolkitBackendConfigSource is a utility class to read configuration data
+ * from a set of prioritized key-value files in a given directory.
+ */
+
+struct _PolkitBackendConfigSourcePrivate
+{
+ GFile *directory;
+
+ GFileMonitor *directory_monitor;
+
+ /* sorted according to priority, higher priority is first */
+ GList *key_files;
+
+ gboolean has_data;
+};
+
+enum
+{
+ PROP_0,
+ PROP_DIRECTORY,
+};
+
+enum
+{
+ CHANGED_SIGNAL,
+ LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+static void polkit_backend_config_source_purge (PolkitBackendConfigSource *source);
+
+static void polkit_backend_config_source_ensure (PolkitBackendConfigSource *source);
+
+G_DEFINE_TYPE (PolkitBackendConfigSource, polkit_backend_config_source, G_TYPE_OBJECT);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+polkit_backend_config_source_init (PolkitBackendConfigSource *source)
+{
+ source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source,
+ POLKIT_BACKEND_TYPE_CONFIG_SOURCE,
+ PolkitBackendConfigSourcePrivate);
+}
+
+static void
+polkit_backend_config_source_finalize (GObject *object)
+{
+ PolkitBackendConfigSource *source = POLKIT_BACKEND_CONFIG_SOURCE (object);
+
+ if (source->priv->directory != NULL)
+ g_object_unref (source->priv->directory);
+
+ if (source->priv->directory_monitor != NULL)
+ g_object_unref (source->priv->directory_monitor);
+
+ g_list_foreach (source->priv->key_files, (GFunc) g_key_file_free, NULL);
+ g_list_free (source->priv->key_files);
+
+ if (G_OBJECT_CLASS (polkit_backend_config_source_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (polkit_backend_config_source_parent_class)->finalize (object);
+}
+
+
+static void
+polkit_backend_config_source_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PolkitBackendConfigSource *source = POLKIT_BACKEND_CONFIG_SOURCE (object);
+
+ switch (prop_id)
+ {
+ case PROP_DIRECTORY:
+ g_value_set_object (value, source->priv->directory);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+polkit_backend_config_source_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PolkitBackendConfigSource *source = POLKIT_BACKEND_CONFIG_SOURCE (object);
+
+ switch (prop_id)
+ {
+ case PROP_DIRECTORY:
+ source->priv->directory = g_value_dup_object (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+directory_monitor_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ gpointer user_data)
+{
+ PolkitBackendConfigSource *source;
+
+ source = POLKIT_BACKEND_CONFIG_SOURCE (user_data);
+
+ if (file != NULL)
+ {
+ gchar *name;
+
+ name = g_file_get_basename (file);
+
+ //g_debug ("event_type=%d file=%p name=%s", event_type, file, name);
+
+ if (!g_str_has_prefix (name, ".") &&
+ !g_str_has_prefix (name, "#") &&
+ g_str_has_suffix (name, ".conf") &&
+ (event_type == G_FILE_MONITOR_EVENT_CREATED ||
+ event_type == G_FILE_MONITOR_EVENT_DELETED ||
+ event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT))
+ {
+
+ //g_debug ("match");
+
+ /* now throw away all caches */
+ polkit_backend_config_source_purge (source);
+ g_signal_emit_by_name (source, "changed");
+ }
+
+ g_free (name);
+ }
+}
+
+static void
+polkit_backend_config_source_constructed (GObject *object)
+{
+ PolkitBackendConfigSource *source = POLKIT_BACKEND_CONFIG_SOURCE (object);
+ GError *error;
+
+ error = NULL;
+ source->priv->directory_monitor = g_file_monitor_directory (source->priv->directory,
+ G_FILE_MONITOR_NONE,
+ NULL,
+ &error);
+ if (source->priv->directory_monitor == NULL)
+ {
+ gchar *dir_name;
+ dir_name = g_file_get_uri (source->priv->directory);
+ g_warning ("Error monitoring directory %s: %s", dir_name, error->message);
+ g_free (dir_name);
+ g_error_free (error);
+ }
+ else
+ {
+ g_signal_connect (source->priv->directory_monitor,
+ "changed",
+ (GCallback) directory_monitor_changed,
+ source);
+ }
+
+ if (G_OBJECT_CLASS (polkit_backend_config_source_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (polkit_backend_config_source_parent_class)->constructed (object);
+}
+
+static void
+polkit_backend_config_source_class_init (PolkitBackendConfigSourceClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->get_property = polkit_backend_config_source_get_property;
+ gobject_class->set_property = polkit_backend_config_source_set_property;
+ gobject_class->finalize = polkit_backend_config_source_constructed;
+ gobject_class->finalize = polkit_backend_config_source_finalize;
+
+ g_type_class_add_private (klass, sizeof (PolkitBackendConfigSourcePrivate));
+
+ /**
+ * PolkitBackendConfigSource:directory:
+ *
+ * The directory to watch for configuration files.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_DIRECTORY,
+ g_param_spec_object ("directory",
+ "Directory",
+ "The directory to watch for configuration files",
+ G_TYPE_FILE,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * PolkitBackendConfiguSource::changed:
+ * @source: A #PolkitBackendConfigSource.
+ *
+ * Emitted when configuration files in #PolkitBackendConfiguSource:directory changes.
+ */
+ signals[CHANGED_SIGNAL] = g_signal_new ("changed",
+ POLKIT_BACKEND_TYPE_CONFIG_SOURCE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PolkitBackendConfigSourceClass, changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+/**
+ * polkit_backend_config_source_new:
+ * @directory: The directory to watch.
+ *
+ * Creates a new #PolkitBackendConfigSource object that reads
+ * configuration from @directory. To watch for configuration changes,
+ * connect to the #PolkitBackendConfigSource::changed signal.
+ *
+ * Returns: A #PolkitBackendConfigSource for @directory. Free with
+ * g_object_unref().
+ **/
+PolkitBackendConfigSource *
+polkit_backend_config_source_new (GFile *directory)
+{
+ PolkitBackendConfigSource *source;
+
+ source = POLKIT_BACKEND_CONFIG_SOURCE (g_object_new (POLKIT_BACKEND_TYPE_CONFIG_SOURCE,
+ "directory", directory,
+ NULL));
+
+ return source;
+}
+
+static void
+polkit_backend_config_source_purge (PolkitBackendConfigSource *source)
+{
+ g_list_foreach (source->priv->key_files, (GFunc) g_key_file_free, NULL);
+ g_list_free (source->priv->key_files);
+ source->priv->key_files = NULL;
+
+ source->priv->has_data = FALSE;
+}
+
+static gint
+compare_filename (GFile *a, GFile *b)
+{
+ gchar *a_uri;
+ gchar *b_uri;
+ gint ret;
+
+ a_uri = g_file_get_uri (a);
+ b_uri = g_file_get_uri (b);
+
+ /* TODO: use ASCII sort function? */
+ ret = -g_strcmp0 (a_uri, b_uri);
+
+ return ret;
+}
+
+static void
+polkit_backend_config_source_ensure (PolkitBackendConfigSource *source)
+{
+ GFileEnumerator *enumerator;
+ GFileInfo *file_info;
+ GError *error;
+ GList *files;
+ GList *l;
+
+ files = NULL;
+
+ if (source->priv->has_data)
+ goto out;
+
+ polkit_backend_config_source_purge (source);
+
+ error = NULL;
+ enumerator = g_file_enumerate_children (source->priv->directory,
+ "standard::*",
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ &error);
+ if (enumerator == NULL)
+ {
+ gchar *dir_name;
+ dir_name = g_file_get_uri (source->priv->directory);
+ g_warning ("Error enumerating files in %s: %s", dir_name, error->message);
+ g_free (dir_name);
+ g_error_free (error);
+ goto out;
+ }
+
+ while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL)
+ {
+ const gchar *name;
+
+ name = g_file_info_get_name (file_info);
+
+ /* only consider files ending in .conf */
+ if (g_str_has_suffix (name, ".conf"))
+ files = g_list_prepend (files, g_file_get_child (source->priv->directory, name));
+
+ g_object_unref (file_info);
+ }
+ g_object_unref (enumerator);
+ if (error != NULL)
+ {
+ g_warning ("Error enumerating files: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ files = g_list_sort (files, (GCompareFunc) compare_filename);
+
+ /* process files; highest priority comes first */
+ for (l = files; l != NULL; l = l->next)
+ {
+ GFile *file = G_FILE (l->data);
+ gchar *filename;
+ GKeyFile *key_file;
+
+ filename = g_file_get_path (file);
+
+ key_file = g_key_file_new ();
+
+ error = NULL;
+ if (!g_key_file_load_from_file (key_file,
+ filename,
+ G_KEY_FILE_NONE,
+ NULL))
+ {
+ g_warning ("Error loading key-file %s: %s", filename, error->message);
+ g_error_free (error);
+ error = NULL;
+ g_key_file_free (key_file);
+ }
+ else
+ {
+ source->priv->key_files = g_list_prepend (source->priv->key_files, key_file);
+ }
+
+ g_free (filename);
+ }
+
+ source->priv->key_files = g_list_reverse (source->priv->key_files);
+
+ out:
+ g_list_foreach (files, (GFunc) g_object_unref, NULL);
+ g_list_free (files);
+}
+
+static GKeyFile *
+find_key_file (PolkitBackendConfigSource *source,
+ const gchar *group,
+ const gchar *key,
+ GError **error)
+{
+ GList *l;
+ GKeyFile *ret;
+
+ ret = NULL;
+
+ for (l = source->priv->key_files; l != NULL; l = l->next)
+ {
+ GKeyFile *key_file = l->data;
+
+ if (g_key_file_has_key (key_file, group, key, NULL))
+ {
+ ret = key_file;
+ goto out;
+ }
+ }
+
+ out:
+ if (ret == NULL)
+ g_set_error_literal (error,
+ G_KEY_FILE_ERROR,
+ G_KEY_FILE_ERROR_NOT_FOUND,
+ "Group/Key combo not found in any config file");
+ return ret;
+}
+
+/**
+ * polkit_backend_config_source_get_integer:
+ * @source: A PolkitBackendConfigSource.
+ * @group: A group name.
+ * @key: A key name.
+ * @error: Return location for error or %NULL.
+ *
+ * Gets the value associated with @key under @group_name.
+ *
+ * Returns: The value or 0 if @error is set.
+ **/
+gint
+polkit_backend_config_source_get_integer (PolkitBackendConfigSource *source,
+ const gchar *group,
+ const gchar *key,
+ GError **error)
+{
+ GKeyFile *key_file;
+
+ polkit_backend_config_source_ensure (source);
+
+ key_file = find_key_file (source, group, key, error);
+ if (key_file == NULL)
+ return 0;
+
+ return g_key_file_get_integer (key_file, group, key, error);
+}
+
+/**
+ * polkit_backend_config_source_get_boolean:
+ * @source: A PolkitBackendConfigSource.
+ * @group: A group name.
+ * @key: A key name.
+ * @error: Return location for error or %NULL.
+ *
+ * Gets the value associated with @key under @group_name.
+ *
+ * Returns: The value or %FALSE if @error is set.
+ **/
+gboolean
+polkit_backend_config_source_get_boolean (PolkitBackendConfigSource *source,
+ const gchar *group,
+ const gchar *key,
+ GError **error)
+{
+ GKeyFile *key_file;
+
+ polkit_backend_config_source_ensure (source);
+
+ key_file = find_key_file (source, group, key, error);
+ if (key_file == NULL)
+ return FALSE;
+
+ return g_key_file_get_boolean (key_file, group, key, error);
+}
+
+/**
+ * polkit_backend_config_source_get_double:
+ * @source: A PolkitBackendConfigSource.
+ * @group: A group name.
+ * @key: A key name.
+ * @error: Return location for error or %NULL.
+ *
+ * Gets the value associated with @key under @group_name.
+ *
+ * Returns: The value or 0.0 if @error is set.
+ **/
+gdouble
+polkit_backend_config_source_get_double (PolkitBackendConfigSource *source,
+ const gchar *group,
+ const gchar *key,
+ GError **error)
+{
+ GKeyFile *key_file;
+
+ polkit_backend_config_source_ensure (source);
+
+ key_file = find_key_file (source, group, key, error);
+ if (key_file == NULL)
+ return 0.0;
+
+ return g_key_file_get_double (key_file, group, key, error);
+}
+
+/**
+ * polkit_backend_config_source_get_string:
+ * @source: A PolkitBackendConfigSource.
+ * @group: A group name.
+ * @key: A key name.
+ * @error: Return location for error or %NULL.
+ *
+ * Gets the value associated with @key under @group_name.
+ *
+ * Returns: The value or %NULL if @error is set.
+ **/
+gchar *
+polkit_backend_config_source_get_string (PolkitBackendConfigSource *source,
+ const gchar *group,
+ const gchar *key,
+ GError **error)
+{
+ GKeyFile *key_file;
+
+ polkit_backend_config_source_ensure (source);
+
+ key_file = find_key_file (source, group, key, error);
+ if (key_file == NULL)
+ return NULL;
+
+ return g_key_file_get_string (key_file, group, key, error);
+}
+
+/**
+ * polkit_backend_config_source_get_string_list:
+ * @source: A PolkitBackendConfigSource.
+ * @group: A group name.
+ * @key: A key name.
+ * @error: Return location for error or %NULL.
+ *
+ * Gets the values associated with @key under @group_name.
+ *
+ * Returns: The value or %NULL if @error is set.
+ **/
+gchar **
+polkit_backend_config_source_get_string_list (PolkitBackendConfigSource *source,
+ const gchar *group,
+ const gchar *key,
+ GError **error)
+{
+ GKeyFile *key_file;
+
+ polkit_backend_config_source_ensure (source);
+
+ key_file = find_key_file (source, group, key, error);
+ if (key_file == NULL)
+ return NULL;
+
+ return g_key_file_get_string_list (key_file, group, key, NULL, error);
+}
diff --git a/src/polkitbackend/polkitbackendconfigsource.h b/src/polkitbackend/polkitbackendconfigsource.h
new file mode 100644
index 0000000..f83a377
--- /dev/null
+++ b/src/polkitbackend/polkitbackendconfigsource.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ */
+
+#if !defined (_POLKIT_BACKEND_COMPILATION) && !defined(_POLKIT_BACKEND_INSIDE_POLKIT_BACKEND_H)
+#error "Only <polkitbackend/polkitbackend.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __POLKIT_BACKEND_CONFIG_SOURCE_H
+#define __POLKIT_BACKEND_CONFIG_SOURCE_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <polkitbackend/polkitbackendtypes.h>
+
+G_BEGIN_DECLS
+
+#define POLKIT_BACKEND_TYPE_CONFIG_SOURCE (polkit_backend_config_source_get_type ())
+#define POLKIT_BACKEND_CONFIG_SOURCE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), POLKIT_BACKEND_TYPE_CONFIG_SOURCE, PolkitBackendConfigSource))
+#define POLKIT_BACKEND_CONFIG_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), POLKIT_BACKEND_TYPE_CONFIG_SOURCE, PolkitBackendConfigSourceClass))
+#define POLKIT_BACKEND_CONFIG_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), POLKIT_BACKEND_TYPE_CONFIG_SOURCE,PolkitBackendConfigSourceClass))
+#define POLKIT_BACKEND_IS_CONFIG_SOURCE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), POLKIT_BACKEND_TYPE_CONFIG_SOURCE))
+#define POLKIT_BACKEND_IS_CONFIG_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), POLKIT_BACKEND_TYPE_CONFIG_SOURCE))
+
+typedef struct _PolkitBackendConfigSourceClass PolkitBackendConfigSourceClass;
+typedef struct _PolkitBackendConfigSourcePrivate PolkitBackendConfigSourcePrivate;
+
+struct _PolkitBackendConfigSource
+{
+ GObject parent_instance;
+ PolkitBackendConfigSourcePrivate *priv;
+};
+
+struct _PolkitBackendConfigSourceClass
+{
+ /*< public >*/
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*changed) (PolkitBackendConfigSource *config_source);
+
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*_polkit_reserved1) (void);
+ void (*_polkit_reserved2) (void);
+ void (*_polkit_reserved3) (void);
+ void (*_polkit_reserved4) (void);
+ void (*_polkit_reserved5) (void);
+ void (*_polkit_reserved6) (void);
+ void (*_polkit_reserved7) (void);
+ void (*_polkit_reserved8) (void);
+};
+
+GType polkit_backend_config_source_get_type (void) G_GNUC_CONST;
+PolkitBackendConfigSource *polkit_backend_config_source_new (GFile *directory);
+gint polkit_backend_config_source_get_integer (PolkitBackendConfigSource *source,
+ const gchar *group,
+ const gchar *key,
+ GError **error);
+gboolean polkit_backend_config_source_get_boolean (PolkitBackendConfigSource *source,
+ const gchar *group,
+ const gchar *key,
+ GError **error);
+gdouble polkit_backend_config_source_get_double (PolkitBackendConfigSource *source,
+ const gchar *group,
+ const gchar *key,
+ GError **error);
+gchar *polkit_backend_config_source_get_string (PolkitBackendConfigSource *source,
+ const gchar *group,
+ const gchar *key,
+ GError **error);
+gchar **polkit_backend_config_source_get_string_list (PolkitBackendConfigSource *source,
+ const gchar *group,
+ const gchar *key,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __POLKIT_BACKEND_CONFIG_SOURCE_H */
+
diff --git a/src/polkitbackend/polkitbackendlocalauthority.c b/src/polkitbackend/polkitbackendlocalauthority.c
index b0d4063..7bbbe2d 100644
--- a/src/polkitbackend/polkitbackendlocalauthority.c
+++ b/src/polkitbackend/polkitbackendlocalauthority.c
@@ -30,6 +30,7 @@
#include "polkitbackendlocalauthority.h"
#include "polkitbackendactionpool.h"
#include "polkitbackendsessionmonitor.h"
+#include "polkitbackendconfigsource.h"
#include <polkit/polkitprivate.h>
@@ -49,6 +50,8 @@ typedef struct
PolkitBackendSessionMonitor *session_monitor;
+ PolkitBackendConfigSource *config_source;
+
GHashTable *hash_identity_to_authority_store;
GHashTable *hash_session_to_authentication_agent;
@@ -117,6 +120,10 @@ static gboolean check_temporary_authorization_for_identity (PolkitBackendLocalAu
PolkitSubject *subject,
const gchar *action_id);
+static GList *get_users_in_group (PolkitBackendLocalAuthority *authority,
+ PolkitIdentity *group,
+ gboolean include_root);
+
static GList *get_groups_for_user (PolkitBackendLocalAuthority *authority,
PolkitIdentity *user);
@@ -244,19 +251,22 @@ static void
polkit_backend_local_authority_init (PolkitBackendLocalAuthority *authority)
{
PolkitBackendLocalAuthorityPrivate *priv;
- GFile *action_desc_directory;
+ GFile *directory;
priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (authority);
- action_desc_directory = g_file_new_for_path (PACKAGE_DATA_DIR "/polkit-1/actions");
- priv->action_pool = polkit_backend_action_pool_new (action_desc_directory);
- g_object_unref (action_desc_directory);
-
+ directory = g_file_new_for_path (PACKAGE_DATA_DIR "/polkit-1/actions");
+ priv->action_pool = polkit_backend_action_pool_new (directory);
+ g_object_unref (directory);
g_signal_connect (priv->action_pool,
"changed",
(GCallback) action_pool_changed,
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);
+
priv->hash_identity_to_authority_store = g_hash_table_new_full ((GHashFunc) polkit_identity_hash,
(GEqualFunc) polkit_identity_equal,
(GDestroyNotify) g_object_unref,
@@ -282,6 +292,9 @@ polkit_backend_local_authority_finalize (GObject *object)
if (priv->action_pool != NULL)
g_object_unref (priv->action_pool);
+ if (priv->config_source != NULL)
+ g_object_unref (priv->config_source);
+
if (priv->session_monitor != NULL)
g_object_unref (priv->session_monitor);
@@ -1694,6 +1707,67 @@ authentication_agent_begin_callback (GObject *source_object,
authentication_session_free (session);
}
+static GList *
+get_admin_auth_identities (PolkitBackendLocalAuthority *authority)
+{
+ PolkitBackendLocalAuthorityPrivate *priv;
+ GList *ret;
+ guint n;
+ gchar **admin_identities;
+ GError *error;
+
+ priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (authority);
+
+ error = NULL;
+ admin_identities = polkit_backend_config_source_get_string_list (priv->config_source,
+ "Configuration",
+ "AdminIdentities",
+ &error);
+ if (admin_identities == NULL)
+ {
+ g_warning ("Error getting admin_identities configuration item: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ for (n = 0; admin_identities[n] != NULL; n++)
+ {
+ PolkitIdentity *identity;
+
+ error = NULL;
+ identity = polkit_identity_from_string (admin_identities[n], &error);
+ if (identity == NULL)
+ {
+ g_warning ("Error parsing identity %s: %s", admin_identities[n], error->message);
+ g_error_free (error);
+ continue;
+ }
+
+ if (POLKIT_IS_UNIX_USER (identity))
+ {
+ ret = g_list_append (ret, identity);
+ }
+ else if (POLKIT_IS_UNIX_GROUP (identity))
+ {
+ ret = g_list_concat (ret, get_users_in_group (authority, identity, FALSE));
+ }
+ else
+ {
+ g_warning ("Unsupported identity %s", admin_identities[n]);
+ }
+ }
+
+ g_strfreev (admin_identities);
+
+ out:
+
+ /* default to uid 0 if no admin identities has been found */
+ if (ret == NULL)
+ ret = g_list_prepend (ret, polkit_unix_user_new (0));
+
+ return ret;
+}
+
static void
authentication_agent_initiate_challenge (AuthenticationAgent *agent,
PolkitSubject *subject,
@@ -1715,14 +1789,18 @@ authentication_agent_initiate_challenge (AuthenticationAgent *agent,
cookie = authentication_agent_new_cookie (agent);
- /* TODO: add uid 0 OR users in wheel group depending on value of @implicit_authorization */
identities = NULL;
- identities = g_list_prepend (identities, g_object_ref (user_of_subject));
-#if 0
- identities = g_list_prepend (identities, polkit_unix_user_new (501));
- identities = g_list_prepend (identities, polkit_unix_user_new (502));
- identities = g_list_prepend (identities, polkit_unix_user_new (0));
-#endif
+
+ /* select admin user if required by the implicit authorization */
+ if (implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_ADMINISTRATOR_AUTHENTICATION_REQUIRED ||
+ implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_ADMINISTRATOR_AUTHENTICATION_REQUIRED_RETAINED)
+ {
+ identities = get_admin_auth_identities (authority);
+ }
+ else
+ {
+ identities = g_list_prepend (identities, g_object_ref (user_of_subject));
+ }
session = authentication_session_new (agent,
cookie,
@@ -2605,6 +2683,53 @@ check_temporary_authorization_for_identity (PolkitBackendLocalAuthority *authori
}
static GList *
+get_users_in_group (PolkitBackendLocalAuthority *authority,
+ PolkitIdentity *group,
+ gboolean include_root)
+{
+ gid_t gid;
+ struct group *grp;
+ GList *ret;
+ guint n;
+
+ ret = NULL;
+
+ gid = polkit_unix_group_get_gid (POLKIT_UNIX_GROUP (group));
+ grp = getgrgid (gid);
+ if (grp == NULL)
+ {
+ g_warning ("Error looking up group with gid %d: %m", gid);
+ goto out;
+ }
+
+ for (n = 0; grp->gr_mem != NULL && grp->gr_mem[n] != NULL; n++)
+ {
+ PolkitIdentity *user;
+ GError *error;
+
+ if (!include_root && strcmp (grp->gr_mem[n], "root") == 0)
+ continue;
+
+ error = NULL;
+ user = polkit_unix_user_new_for_name (grp->gr_mem[n], &error);
+ if (user == NULL)
+ {
+ g_warning ("Unknown username '%s' in group: %s", grp->gr_mem[n], error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ ret = g_list_prepend (ret, user);
+ }
+ }
+
+ ret = g_list_reverse (ret);
+
+ out:
+ return ret;
+}
+
+static GList *
get_groups_for_user (PolkitBackendLocalAuthority *authority,
PolkitIdentity *user)
{
diff --git a/src/polkitbackend/polkitbackendtypes.h b/src/polkitbackend/polkitbackendtypes.h
index b2b0111..0e6d24a 100644
--- a/src/polkitbackend/polkitbackendtypes.h
+++ b/src/polkitbackend/polkitbackendtypes.h
@@ -33,6 +33,8 @@ typedef struct _PolkitBackendLocalAuthority PolkitBackendLocalAuthority;
struct _PolkitBackendSessionMonitor;
typedef struct _PolkitBackendSessionMonitor PolkitBackendSessionMonitor;
+struct _PolkitBackendConfigSource;
+typedef struct _PolkitBackendConfigSource PolkitBackendConfigSource;
#endif /* __POLKIT_BACKEND_TYPES_H */