Commit 2d65587f authored by David Zeuthen's avatar David Zeuthen

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.
parent d288deca
......@@ -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
......
......@@ -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">
......
......@@ -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>
......@@ -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
#
# 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
......@@ -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);
}
/* ---------------------------------------------------------------------------------------------------- */
......
#
# 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
......@@ -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 :
......
......@@ -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 */
......
/*
* 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)
{