Commit f3d4f5ae authored by Robert Ancell's avatar Robert Ancell

polkitbackend: Re-instate the local authority

The local authority was removed in 0f830c76 (May 2012) as it was deemed
unnecessary as the jsbackend could perform any functionality that was
previously done using the localbackend.

However, for security reasons Debian and Ubuntu did not determine the JS
backend safe enough to ship by default, and thus have remained on polkit
version 105 ever since (though collecting cherry-picked patches from the
following releases).

By re-instating the local authority both Debian and Ubuntu are able to
update to track the latest version of polkit. The JS backend remains by
default and the local backend is only compiled and used if configured
with --disable-javascript.

While supporting two backends does come at an increased cost in this
case it seems reasonable low as the code in this change required almost
no modification to re-introduce.
parent 3eadcff2
Pipeline #111754 passed with stage
in 2 minutes and 52 seconds
......@@ -79,7 +79,22 @@ PKG_CHECK_MODULES(GLIB, [gmodule-2.0 gio-unix-2.0 >= 2.30.0])
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
PKG_CHECK_MODULES(LIBJS, [mozjs-60])
AC_ARG_ENABLE([javascript],
[AS_HELP_STRING([--enable-javascript[=@<:@auto/yes/no@:>@]], [Use javascript (auto/yes/no)])],
[enable_javascript=$enableval],
[enable_javascript=auto])
have_mozjs="no"
if test "$enable_javascript" != "no"; then
PKG_CHECK_MODULES(LIBJS, [mozjs-60], [
have_mozjs="yes"
AC_DEFINE([HAVE_LIBJS], 1, [Define to 1 if libmozjs is available])
], [
if test "$enable_javascript" = "yes"; then
AC_MSG_ERROR([javascript support requested but mozjs library not found])
fi
])
fi
AM_CONDITIONAL([HAVE_LIBJS], [test "${have_mozjs}" = "yes"])
AC_SUBST(LIBJS_CFLAGS)
AC_SUBST(LIBJS_CXXFLAGS)
......@@ -579,7 +594,8 @@ echo "
Session tracking: ${SESSION_TRACKING}
PAM support: ${have_pam}
systemdsystemunitdir: ${systemdsystemunitdir}
polkitd user: ${POLKITD_USER}"
polkitd user: ${POLKITD_USER}
JS backend: ${have_mozjs}"
if test "$have_pam" = yes ; then
echo "
......
......@@ -3,6 +3,7 @@
[encoding: UTF-8]
actions/org.freedesktop.policykit.policy.in
src/examples/org.freedesktop.policykit.examples.pkexec.policy.in
src/polkitbackend/polkitbackendlocalauthority.c
src/programs/pkaction.c
src/programs/pkcheck.c
src/programs/pkexec.c
......
# Configuration file for the PolicyKit Local Authority.
#
# DO NOT EDIT THIS FILE, it will be overwritten on update.
#
# See the pklocalauthority(8) man page for more information
# about configuring the Local Authority.
#
[Configuration]
AdminIdentities=unix-group:wheel
......@@ -33,11 +33,18 @@ libpolkit_backend_1_la_SOURCES = \
polkitbackendprivate.h \
polkitbackendauthority.h polkitbackendauthority.c \
polkitbackendinteractiveauthority.h polkitbackendinteractiveauthority.c \
polkitbackendjsauthority.h polkitbackendjsauthority.cpp \
polkitbackendlocalauthority.h polkitbackendlocalauthority.c \
polkitbackendlocalauthorizationstore.h polkitbackendlocalauthorizationstore.c \
polkitbackendactionpool.h polkitbackendactionpool.c \
polkitbackendconfigsource.h polkitbackendconfigsource.c \
polkitbackendactionlookup.h polkitbackendactionlookup.c \
$(NULL)
if HAVE_LIBJS
libpolkit_backend_1_la_SOURCES += \
polkitbackendjsauthority.h polkitbackendjsauthority.cpp
endif
if HAVE_LIBSYSTEMD
libpolkit_backend_1_la_SOURCES += \
polkitbackendsessionmonitor.h polkitbackendsessionmonitor-systemd.c
......@@ -96,9 +103,13 @@ polkitd_LDADD = \
CLEANFILES = $(BUILT_SOURCES)
localauthorityconfigdir = $(sysconfdir)/polkit-1/localauthority.conf.d
localauthorityconfig_DATA = 50-localauthority.conf
EXTRA_DIST = \
init.js \
toarray.pl \
$(localauthorityconfig_DATA) \
$(rules_DATA) \
$(NULL)
......@@ -109,6 +120,12 @@ clean-local :
rm -f *~ $(BUILT_SOURCES)
install-data-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)$(sysconfdir)/polkit-1/rules.d
-chmod 700 $(DESTDIR)$(sysconfdir)/polkit-1/rules.d
-chown $(POLKITD_USER) $(DESTDIR)$(sysconfdir)/polkit-1/rules.d
......
......@@ -31,6 +31,7 @@
#include "polkitbackendauthority.h"
#include "polkitbackendjsauthority.h"
#include "polkitbackendlocalauthority.h"
#include "polkitbackendprivate.h"
......@@ -1431,7 +1432,11 @@ polkit_backend_authority_get (void)
LOG_PID,
LOG_AUTHPRIV); /* security/authorization messages (private) */
#ifdef HAVE_LIBJS
authority = POLKIT_BACKEND_AUTHORITY (g_object_new (POLKIT_BACKEND_TYPE_JS_AUTHORITY, NULL));
#else
authority = POLKIT_BACKEND_AUTHORITY (g_object_new (POLKIT_BACKEND_TYPE_LOCAL_AUTHORITY, NULL));
#endif
return authority;
}
......
/*
* 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"
/* <internal>
* SECTION:polkitbackendconfigsource
* @title: PolkitBackendConfigSource
* @short_description: Access configuration files
*
* The #PolkitBackendConfigSource class 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->constructed = 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::name",
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);
source->priv->has_data = TRUE;
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