Commit f631d726 authored by David Zeuthen's avatar David Zeuthen

add API for overriding defaults and make polkit-action(1) use this API.

parent c359201a
......@@ -530,6 +530,9 @@ if test "${POLKIT_AUTHDB}" = default ; then
echo "NOTE: The directories ${localstatedir}/run/PolicyKit and ${localstatedir}/lib/PolicyKit will be"
echo " owned by group ${POLKIT_GROUP} and will be mode 770."
echo
echo "NOTE: The directory ${localstatedir}/run/PolicyKit-public will be"
echo " owned by group ${POLKIT_GROUP} and will be mode 775."
echo
echo "NOTE: ${libexecdir}/polkit-read-auth-helper will be owned by"
echo " group ${POLKIT_GROUP} and installed with mode 2755 (setgid binary)."
echo
......
......@@ -13,13 +13,18 @@
<refnamediv>
<refname>polkit-action</refname>
<refpurpose>List registered PolicyKit actions</refpurpose>
<refpurpose>List and modify registered PolicyKit actions</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>polkit-action</command>
<arg><option>--action <replaceable>action</replaceable></option></arg>
<arg><option>--reset-defaults <replaceable>action</replaceable></option></arg>
<arg><option>--show-overrides</option></arg>
<arg><option>--set-defaults-any <replaceable>action</replaceable> <replaceable>value</replaceable></option></arg>
<arg><option>--set-defaults-inactive <replaceable>action</replaceable> <replaceable>value</replaceable></option></arg>
<arg><option>--set-defaults-active <replaceable>action</replaceable> <replaceable>value</replaceable></option></arg>
<arg><option>--version</option></arg>
<arg><option>--help</option></arg>
</cmdsynopsis>
......@@ -28,8 +33,8 @@
<refsect1>
<title>DESCRIPTION</title>
<para>
polkit-action is used to list the PolicyKit actions that are
registered on the system.
polkit-action is used to list and modify the PolicyKit actions
that are registered on the system.
</para>
</refsect1>
......@@ -44,6 +49,93 @@
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--reset-defaults <replaceable>action</replaceable></option></term>
<listitem>
<para>
Reset the defaults for the specified action to the factory
defaults. The authorization needed to do this is
<emphasis>org.freedesktop.policykit.modify-defaults</emphasis>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--show-overrides</option></term>
<listitem>
<para>
Prints all actions for where the defaults are overridden.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--set-defaults-any <replaceable>action</replaceable> <replaceable>value</replaceable></option></term>
<listitem>
<para>
Override the <emphasis>any</emphasis> stanza for the given
action with the supplied value. The authorization needed
to do this is <emphasis>org.freedesktop.policykit.modify-defaults</emphasis>.
Valid values for <emphasis>value</emphasis> are
<emphasis>no</emphasis>,
<emphasis>auth_admin_one_shot</emphasis>,
<emphasis>auth_admin</emphasis>,
<emphasis>auth_admin_keep_session</emphasis>,
<emphasis>auth_admin_keep_always</emphasis>,
<emphasis>auth_self_one_shot</emphasis>,
<emphasis>auth_self</emphasis>,
<emphasis>auth_self_keep_session</emphasis>,
<emphasis>auth_self_keep_always</emphasis>,
and <emphasis>yes</emphasis>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--set-defaults-inactive <replaceable>action</replaceable> <replaceable>value</replaceable></option></term>
<listitem>
<para>
Override the <emphasis>inactive</emphasis> stanza for the given
action with the supplied value. The authorization needed
to do this is <emphasis>org.freedesktop.policykit.modify-defaults</emphasis>.
Valid values for <emphasis>value</emphasis> are
<emphasis>no</emphasis>,
<emphasis>auth_admin_one_shot</emphasis>,
<emphasis>auth_admin</emphasis>,
<emphasis>auth_admin_keep_session</emphasis>,
<emphasis>auth_admin_keep_always</emphasis>,
<emphasis>auth_self_one_shot</emphasis>,
<emphasis>auth_self</emphasis>,
<emphasis>auth_self_keep_session</emphasis>,
<emphasis>auth_self_keep_always</emphasis>,
and <emphasis>yes</emphasis>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--set-defaults-active <replaceable>action</replaceable> <replaceable>value</replaceable></option></term>
<listitem>
<para>
Override the <emphasis>active</emphasis> stanza for the given
action with the supplied value. The authorization needed
to do this is <emphasis>org.freedesktop.policykit.modify-defaults</emphasis>.
Valid values for <emphasis>value</emphasis> are
<emphasis>no</emphasis>,
<emphasis>auth_admin_one_shot</emphasis>,
<emphasis>auth_admin</emphasis>,
<emphasis>auth_admin_keep_session</emphasis>,
<emphasis>auth_admin_keep_always</emphasis>,
<emphasis>auth_self_one_shot</emphasis>,
<emphasis>auth_self</emphasis>,
<emphasis>auth_self_keep_session</emphasis>,
<emphasis>auth_self_keep_always</emphasis>,
and <emphasis>yes</emphasis>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--version</option></term>
......@@ -69,12 +161,12 @@
<title>COMPLETION</title>
<para>
PolicyKit ships with a collection of shell functions such that
completion on actions works when using the
completion on options, <emphasis>action</emphasis>
and <emphasis>value</emphasis> works when using the
<citerefentry>
<refentrytitle>bash</refentrytitle><manvolnum>1</manvolnum>
</citerefentry>
shell. For polkit-action, completion is enabled for
the <option>--action</option> argument.
shell.
</para>
</refsect1>
......
......@@ -46,4 +46,14 @@ file are instantly applied.
</defaults>
</action>
<action id="org.freedesktop.policykit.modify-defaults">
<_description>Modify defaults for implicit authorizations</_description>
<_message>Authentication is required to modify the defaults for implicit authorizations</_message>
<defaults>
<allow_any>no</allow_any>
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin_keep_always</allow_active>
</defaults>
</action>
</policyconfig>
......@@ -60,7 +60,8 @@
* Reads an entire file into allocated memory.
*
* Returns: #TRUE if the file was read into memory; #FALSE if an error
* occured and errno will be set.
* occured and errno will be set. On OOM, errno will be set to
* ENOMEM. If the file doesn't exist, errno will be set to ENOENT.
*/
kit_bool_t
kit_file_get_contents (const char *path, char **out_contents, size_t *out_contents_size)
......@@ -81,9 +82,10 @@ kit_file_get_contents (const char *path, char **out_contents, size_t *out_conten
fd = -1;
ret = FALSE;
*out_contents = NULL;
p = NULL;
fd = open (path, O_RDONLY);
if (fd == 0)
if (fd == -1)
goto out;
p = kit_malloc (BUF_SIZE);
......
......@@ -198,23 +198,27 @@ kit_spawn_sync (const char *working_directory,
envp_to_use = environ;
if (stdin != NULL) {
if (pipe (stdin_pipe) != 0)
if (pipe (stdin_pipe) != 0) {
goto out;
}
}
if (stdout != NULL) {
if (pipe (stdout_pipe) != 0)
if (pipe (stdout_pipe) != 0) {
goto out;
}
}
if (stderr != NULL) {
if (pipe (stderr_pipe) != 0)
if (pipe (stderr_pipe) != 0) {
goto out;
}
}
pid = fork ();
if (pid == -1)
if (pid == -1) {
goto out;
}
if (pid == 0) {
/* child */
......@@ -326,6 +330,7 @@ kit_spawn_sync (const char *working_directory,
NULL);
if (ret < 0 && errno != EINTR) {
kit_warning ("4");
goto out;
}
......@@ -333,6 +338,7 @@ kit_spawn_sync (const char *working_directory,
num_written = _write_to (stdin_pipe[1], wp);
if (num_written == -1) {
kit_warning ("3");
goto out;
}
......@@ -349,6 +355,7 @@ kit_spawn_sync (const char *working_directory,
close (stdout_pipe[0]);
stdout_pipe[0] = -1;
} else if (num_read == -1) {
kit_warning ("2");
goto out;
}
}
......@@ -359,12 +366,14 @@ kit_spawn_sync (const char *working_directory,
close (stderr_pipe[0]);
stderr_pipe[0] = -1;
} else if (num_read == -1) {
kit_warning ("1");
goto out;
}
}
}
if (waitpid (pid, out_exit_status, 0) == -1) {
kit_warning ("0");
goto out;
}
pid = -1;
......@@ -377,6 +386,7 @@ kit_spawn_sync (const char *working_directory,
} else {
ret = FALSE;
errno = WEXITSTATUS (*out_exit_status) - 128;
kit_warning ("kiddo died with errno %d: %m!", errno);
}
out:
......
......@@ -28,19 +28,28 @@ libpolkit_dbus_la_LIBADD = @DBUS_LIBS@ $(top_builddir)/src/polkit/libpolkit.la $
libpolkit_dbus_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
if POLKIT_AUTHDB_DEFAULT
libexec_PROGRAMS = polkit-read-auth-helper
libexec_PROGRAMS = polkit-read-auth-helper polkit-set-default-helper
polkit_read_auth_helper_SOURCES = polkit-read-auth-helper.c
polkit_read_auth_helper_CFLAGS = @DBUS_CFLAGS@
polkit_read_auth_helper_LDADD = $(top_builddir)/src/polkit/libpolkit.la libpolkit-dbus.la
polkit_set_default_helper_SOURCES = polkit-set-default-helper.c
polkit_set_default_helper_CFLAGS = @DBUS_CFLAGS@
polkit_set_default_helper_LDADD = $(top_builddir)/src/polkit/libpolkit.la libpolkit-dbus.la
# polkit-read-auth-helper needs to be setgid $POLKIT_GROUP to be able
# to read authorization files in /var/lib/PolicyKit and
# /var/run/PolicyKit
#
# polkit-set-default-helper needs to be setgid $POLKIT_GROUP to be able
# to write .override files in /var/lib/PolicyKit-public
#
install-exec-hook:
-chgrp $(POLKIT_GROUP) $(DESTDIR)$(libexecdir)/polkit-read-auth-helper
-chmod 2755 $(DESTDIR)$(libexecdir)/polkit-read-auth-helper
-chgrp $(POLKIT_GROUP) $(DESTDIR)$(libexecdir)/polkit-set-default-helper
-chmod 2755 $(DESTDIR)$(libexecdir)/polkit-set-default-helper
endif
## note that TESTS has special meaning (stuff to use in make check)
......
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/***************************************************************************
*
* polkit-set-default-helper.c : setgid polkituser helper for PolicyKit
* to set defaults
*
* Copyright (C) 2007 David Zeuthen, <david@fubar.dk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
#define _GNU_SOURCE
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <security/pam_appl.h>
#include <grp.h>
#include <pwd.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <utime.h>
#include <fcntl.h>
#include <dirent.h>
#include <utime.h>
#include <polkit/polkit-private.h>
#include <polkit-dbus/polkit-dbus.h>
static polkit_bool_t
check_for_auth (uid_t caller_uid, pid_t caller_pid)
{
polkit_bool_t ret;
DBusError error;
DBusConnection *bus;
PolKitCaller *caller;
PolKitAction *action;
PolKitContext *context;
PolKitError *pk_error;
PolKitResult pk_result;
ret = FALSE;
dbus_error_init (&error);
bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
if (bus == NULL) {
fprintf (stderr, "polkit-set-default-helper: cannot connect to system bus: %s: %s\n",
error.name, error.message);
dbus_error_free (&error);
goto out;
}
caller = polkit_caller_new_from_pid (bus, caller_pid, &error);
if (caller == NULL) {
fprintf (stderr, "polkit-set-default-helper: cannot get caller from pid: %s: %s\n",
error.name, error.message);
goto out;
}
action = polkit_action_new ();
if (action == NULL) {
fprintf (stderr, "polkit-set-default-helper: cannot allocate PolKitAction\n");
goto out;
}
if (!polkit_action_set_action_id (action, "org.freedesktop.policykit.modify-defaults")) {
fprintf (stderr, "polkit-set-default-helper: cannot set action_id\n");
goto out;
}
context = polkit_context_new ();
if (context == NULL) {
fprintf (stderr, "polkit-set-default-helper: cannot allocate PolKitContext\n");
goto out;
}
pk_error = NULL;
if (!polkit_context_init (context, &pk_error)) {
fprintf (stderr, "polkit-set-default-helper: cannot initialize polkit context: %s: %s\n",
polkit_error_get_error_name (pk_error),
polkit_error_get_error_message (pk_error));
polkit_error_free (pk_error);
goto out;
}
pk_result = polkit_context_is_caller_authorized (context, action, caller, TRUE, &pk_error);
if (polkit_error_is_set (pk_error)) {
fprintf (stderr, "polkit-set-default-helper: cannot determine if caller is authorized: %s: %s\n",
polkit_error_get_error_name (pk_error),
polkit_error_get_error_message (pk_error));
polkit_error_free (pk_error);
goto out;
}
if (pk_result != POLKIT_RESULT_YES) {
goto out;
}
ret = TRUE;
out:
return ret;
}
static polkit_bool_t
set_default (const char *action_id, const char *any, const char *inactive, const char *active)
{
char *path;
char *contents;
polkit_bool_t ret;
path = NULL;
contents = NULL;
ret = FALSE;
path = kit_strdup_printf (PACKAGE_LOCALSTATE_DIR "/lib/PolicyKit-public/%s.override", action_id);
if (path == NULL)
goto out;
contents = kit_strdup_printf ("%s:%s:%s",
any, inactive, active);
if (contents == NULL)
goto out;
if (!kit_file_set_contents (path, 0464, contents, strlen (contents))) {
kit_warning ("Error writing override file '%s': %m\n", path);
goto out;
}
ret = TRUE;
out:
if (path == NULL)
kit_free (path);
if (contents == NULL)
kit_free (contents);
return ret;
}
static polkit_bool_t
clear_default (const char *action_id)
{
char *path;
polkit_bool_t ret;
ret = FALSE;
path = kit_strdup_printf (PACKAGE_LOCALSTATE_DIR "/lib/PolicyKit-public/%s.override", action_id);
if (path == NULL)
goto out;
if (unlink (path) != 0) {
kit_warning ("Error unlinking file %s: %m", path);
}
ret = TRUE;
out:
if (path == NULL)
kit_free (path);
return ret;
}
int
main (int argc, char *argv[])
{
int ret;
gid_t egid;
struct group *group;
uid_t caller_uid;
struct passwd *pw;
uid_t uid_for_polkit_user;
ret = 1;
/* clear the entire environment to avoid attacks using with libraries honoring environment variables */
if (clearenv () != 0)
goto out;
/* set a minimal environment */
setenv ("PATH", "/usr/sbin:/usr/bin:/sbin:/bin", 1);
openlog ("polkit-set-default-helper", LOG_CONS | LOG_PID, LOG_AUTHPRIV);
/* check for correct invocation */
if (! (argc == 3 || argc == 6)) {
syslog (LOG_NOTICE, "inappropriate use of helper, wrong number of arguments [uid=%d]", getuid ());
fprintf (stderr, "polkit-set-default-helper: wrong number of arguments. This incident has been logged.\n");
goto out;
}
caller_uid = getuid ();
/* check we're running with a non-tty stdin */
if (isatty (STDIN_FILENO) != 0) {
syslog (LOG_NOTICE, "inappropriate use of helper, stdin is a tty [uid=%d]", getuid ());
fprintf (stderr, "polkit-set-default-helper: inappropriate use of helper, stdin is a tty. This incident has been logged.\n");
goto out;
}
/* check that we are setgid polkituser */
egid = getegid ();
group = getgrgid (egid);
if (group == NULL) {
fprintf (stderr, "polkit-set-default-helper: cannot lookup group info for gid %d\n", egid);
goto out;
}
if (strcmp (group->gr_name, POLKIT_GROUP) != 0) {
fprintf (stderr, "polkit-set-default-helper: needs to be setgid " POLKIT_GROUP "\n");
goto out;
}
pw = getpwnam (POLKIT_USER);
if (pw == NULL) {
fprintf (stderr, "polkit-set-default-helper: cannot lookup uid for " POLKIT_USER "\n");
goto out;
}
uid_for_polkit_user = pw->pw_uid;
/*----------------------------------------------------------------------------------------------------*/
/* uid 0 is allowed to set anything */
if (caller_uid != 0) {
/* see if calling user has the
*
* org.freedesktop.policykit.modify-defaults
*
* authorization
*/
if (!check_for_auth (caller_uid, getppid ())) {
goto out;
}
}
PolKitResult any;
PolKitResult inactive;
PolKitResult active;
if (!polkit_action_validate_id (argv[1])) {
goto out;
}
/* sanity check */
if (argc == 3) {
if (strcmp (argv[2], "clear") != 0)
goto out;
if (!clear_default (argv[1]))
goto out;
} else if (argc == 6) {
if (strcmp (argv[2], "set") != 0)
goto out;
if (!polkit_result_from_string_representation (argv[3], &any)) {
goto out;
}
if (!polkit_result_from_string_representation (argv[4], &inactive)) {
goto out;
}
if (!polkit_result_from_string_representation (argv[5], &active)) {
goto out;
}
if (!set_default (argv[1], argv[3], argv[4], argv[5]))
goto out;
} else {
goto out;
}
/* trigger a reload */
if (utimes (PACKAGE_LOCALSTATE_DIR "/lib/misc/PolicyKit.reload", NULL) != 0) {
kit_warning ("Error updating access+modification time on file '%s': %m\n",
PACKAGE_LOCALSTATE_DIR "/lib/misc/PolicyKit.reload");
}
ret = 0;
out:
return ret;
}
......@@ -125,20 +125,26 @@ if POLKIT_AUTHDB_DEFAULT
# polkit-auth-read-helper is used to read it) and the $POLKIT_GROUP
# group needs to be able to write files there.
#
# The /var/lib/PolicyKit-public is used for storing world-readable
# information. Only $POLKIT_GROUP may write to it.
#
# The /var/lib/misc/PolicyKit.reload file is used for triggering that
# authorizations have changed; it needs to be world readable and
# writeable for the $POLKIT_GROUP group (FHS 2.3 suggests that
# location)
#
install-data-local:
-mkdir -p $(DESTDIR)$(localstatedir)/lib/misc
-touch $(DESTDIR)$(localstatedir)/lib/misc/PolicyKit.reload
mkdir -p $(DESTDIR)$(localstatedir)/lib/misc
touch $(DESTDIR)$(localstatedir)/lib/misc/PolicyKit.reload
-chgrp $(POLKIT_GROUP) $(DESTDIR)$(localstatedir)/lib/misc/PolicyKit.reload
-chmod 775 $(DESTDIR)$(localstatedir)/lib/misc/PolicyKit.reload
-mkdir -p $(DESTDIR)$(localstatedir)/lib/PolicyKit
-mkdir -p $(DESTDIR)$(localstatedir)/run/PolicyKit