From 2d65587fbf21bcaacce05798533ffd0900e132d9 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Mon, 9 Feb 2009 21:10:46 -0500 Subject: make it possible to define what administrator authentication means 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. --- docs/TODO | 4 - docs/polkit/polkit-docs.xml | 1 + docs/polkitbackend/polkitbackend-sections.txt | 19 + docs/polkitbackend/polkitbackend.types | 1 + src/nullbackend/50-nullbackend.conf | 13 +- src/nullbackend/polkitbackendnullauthority.c | 122 +---- src/polkitbackend/50-localauthority.conf | 26 ++ src/polkitbackend/Makefile.am | 6 + src/polkitbackend/polkitbackend.h | 1 + src/polkitbackend/polkitbackendconfigsource.c | 563 ++++++++++++++++++++++++ src/polkitbackend/polkitbackendconfigsource.h | 97 ++++ src/polkitbackend/polkitbackendlocalauthority.c | 149 ++++++- src/polkitbackend/polkitbackendtypes.h | 2 + 13 files changed, 868 insertions(+), 136 deletions(-) create mode 100644 src/polkitbackend/50-localauthority.conf create mode 100644 src/polkitbackend/polkitbackendconfigsource.c create mode 100644 src/polkitbackend/polkitbackendconfigsource.h 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 @@ + 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 + +
+polkitbackendconfigsource +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 + +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 +
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: +# unix-group: +# +# where is username/uid and 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 #include #include +#include #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 + */ + +#include "config.h" + +#include +#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 + */ + +#if !defined (_POLKIT_BACKEND_COMPILATION) && !defined(_POLKIT_BACKEND_INSIDE_POLKIT_BACKEND_H) +#error "Only 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 +#include +#include + +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 @@ -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, @@ -2604,6 +2682,53 @@ check_temporary_authorization_for_identity (PolkitBackendLocalAuthority *authori return result; } +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 */ -- cgit v1.2.3