There's really no reason to run all this code as uid 0.
Signed-off-by: David Zeuthen <davidz@redhat.com>
fi
AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$systemdsystemunitdir"])
+dnl ---------------------------------------------------------------------------
+dnl - User for running polkitd
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_WITH(polkitd_user, AS_HELP_STRING([--with-polkitd-user=<user>],[User for running polkitd (polkitd)]))
+
+if test -z "$with_polkitd_user" ; then
+ POLKITD_USER=polkitd
+else
+ POLKITD_USER=$with_polkitd_user
+fi
+AC_SUBST(POLKITD_USER)
+AC_DEFINE_UNQUOTED(POLKITD_USER,"$POLKITD_USER", [User for running polkitd])
+
dnl ---------------------------------------------------------------------------
dnl - Select which authentication framework to use
dnl ---------------------------------------------------------------------------
Authentication framework: ${POLKIT_AUTHFW}
Session tracking: ${SESSION_TRACKING}
PAM support: ${have_pam}
- systemdsystemunitdir: ${systemdsystemunitdir}"
+ systemdsystemunitdir: ${systemdsystemunitdir}
+ polkitd user: ${POLKITD_USER}"
if test "$have_pam" = yes ; then
echo "
echo " have mode 4755 (setuid root binary)"
echo
-echo "NOTE: The directory ${sysconfdir}/polkit-1/rules.d"
-echo " should have mode 700"
+echo "NOTE: The directory ${sysconfdir}/polkit-1/rules.d must be owned"
+echo " by user '$POLKITD_USER' and have mode 700"
echo
-echo "NOTE: The directory ${datadir}/polkit-1/rules.d"
-echo " should have mode 700"
+echo "NOTE: The directory ${datadir}/polkit-1/rules.d must be owned"
+echo " by user '$POLKITD_USER' and have mode 700"
echo
libprivdir = $(prefix)/lib/polkit-1
+# ----------------------------------------------------------------------------------------------------
+
servicedir = $(datadir)/dbus-1/system-services
service_in_files = org.freedesktop.PolicyKit1.service.in
service_DATA = $(service_in_files:.service.in=.service)
$(service_DATA): $(service_in_files) Makefile
@sed -e "s|\@libprivdir\@|$(libprivdir)|" $< > $@
+# ----------------------------------------------------------------------------------------------------
+
dbusconfdir = $(sysconfdir)/dbus-1/system.d
-dbusconf_DATA = org.freedesktop.PolicyKit1.conf
+dbusconf_in_files = org.freedesktop.PolicyKit1.conf.in
+dbusconf_DATA = $(dbusconf_in_files:.conf.in=.conf)
+
+$(dbusconf_DATA): $(dbusconf_in_files) Makefile
+ @sed -e "s|\@polkitd_user\@|$(POLKITD_USER)|" $< > $@
+
+# ----------------------------------------------------------------------------------------------------
if POLKIT_AUTHFW_PAM
pamdir = $(sysconfdir)/pam.d
pam_DATA = polkit-1
endif
+# ----------------------------------------------------------------------------------------------------
+
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = polkit-gobject-1.pc polkit-backend-1.pc polkit-agent-1.pc
+# ----------------------------------------------------------------------------------------------------
systemdservice_in_files = polkit.service.in
@sed -e "s|\@libprivdir\@|$(libprivdir)|" $< > $@
endif
+# ----------------------------------------------------------------------------------------------------
+
CLEANFILES = $(BUILT_SOURCES)
EXTRA_DIST = \
org.freedesktop.PolicyKit1.Authority.xml \
org.freedesktop.PolicyKit1.AuthenticationAgent.xml \
$(service_in_files) \
+ $(dbusconf_in_files) \
$(systemdservice_in_files) \
- $(dbusconf_DATA) \
$(NULL)
clean-local :
- rm -f *~ $(service_DATA) $(systemdservice_DATA)
+ rm -f *~ $(service_DATA) $(dbusconf_DATA) $(systemdservice_DATA)
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
-
-<!DOCTYPE busconfig PUBLIC
- "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
- <policy user="root">
- <allow own="org.freedesktop.PolicyKit1"/>
- </policy>
-
- <policy context="default">
- <allow send_destination="org.freedesktop.PolicyKit1"/>
- </policy>
-
- <!-- Allow uid 0 to send messages on the org.freedesktop.PolicyKit1.AuthenticationAgent interface -->
- <policy user="root">
- <allow send_interface="org.freedesktop.PolicyKit1.AuthenticationAgent"/>
- </policy>
-
-</busconfig>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
+
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy user="@polkitd_user@">
+ <allow own="org.freedesktop.PolicyKit1"/>
+ </policy>
+
+ <policy context="default">
+ <allow send_destination="org.freedesktop.PolicyKit1"/>
+ </policy>
+
+ <!-- Allow uid 0 to send messages on the org.freedesktop.PolicyKit1.AuthenticationAgent interface -->
+ <policy user="@polkitd_user@">
+ <allow send_interface="org.freedesktop.PolicyKit1.AuthenticationAgent"/>
+ </policy>
+
+</busconfig>
untrusted. For every request from a subject, the mechanism needs
to determine if the request is authorized or if it should refuse
to service the subject. Using the polkit APIs, a mechanism can
- offload this decision to a trusted party: The polkit Authority.
+ offload this decision to a trusted party: The polkit authority.
+ </para>
+
+ <para>
+ The polkit authority is implemented as an system daemon,
+ <link linkend="polkitd.8"><citerefentry><refentrytitle>polkitd</refentrytitle><manvolnum>8</manvolnum></citerefentry></link>,
+ which itself has little privilege as it is running as the
+ <emphasis>polkitd</emphasis> system user. Mechanisms, subjects
+ and authentication agents communicate with the authority using
+ the system message bus.
</para>
<para>
<refsect1 id="polkit-declaring-actions"><title>DECLARING ACTIONS</title>
<para>
- A mechanism need to declare a set of <quote>ACTIONS</quote> in
+ A mechanism need to declare a set of <emphasis>actions</emphasis> in
order to use polkit. Actions correspond to operations that
clients can request the mechanism to carry out and are defined
in XML files that the mechanism installs into the <filename
The <function>spawn()</function> method should be used sparingly
as helpers may take a very long or indeterminate amount of time
to complete and no other authorization check can be handled
- while the helper is running.
+ while the helper is running. Note that the spawned programs
+ will run as the unprivileged <emphasis>polkitd</emphasis> system
+ user.
</para>
<para>
whenever an application calls into the service.
</para>
+ <para>
+ <command>polkitd</command> must be started with superuser
+ privileges but drops privileges early by switching to the
+ unprivileged <emphasis>polkitd</emphasis> system user.
+ </para>
+
<para>
See the <link
linkend="polkit.8"><citerefentry><refentrytitle>polkit</refentrytitle><manvolnum>8</manvolnum></citerefentry></link>
clean-local :
rm -f *~ $(BUILT_SOURCES)
-install-exec-hook:
+install-data-hook:
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
mkdir -p $(DESTDIR)$(datadir)/polkit-1/rules.d
-chmod 700 $(DESTDIR)$(datadir)/polkit-1/rules.d
+ -chown $(POLKITD_USER) $(DESTDIR)$(datadir)/polkit-1/rules.d
#include <glib-unix.h>
+#include <pwd.h>
+#include <grp.h>
+
#include <polkit/polkit.h>
#include <polkitbackend/polkitbackend.h>
return FALSE;
}
+static gboolean
+become_user (const gchar *user,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ struct passwd *pw;
+
+ g_return_val_if_fail (user != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ pw = getpwnam (user);
+ if (pw == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Error calling getpwnam(): %m");
+ goto out;
+ }
+
+ if (setgroups (0, NULL) != 0)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Error clearing groups: %m");
+ goto out;
+ }
+ if (initgroups (pw->pw_name, pw->pw_gid) != 0)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Error initializing groups: %m");
+ goto out;
+ }
+
+ setregid (pw->pw_gid, pw->pw_gid);
+ setreuid (pw->pw_uid, pw->pw_uid);
+ if ((geteuid () != pw->pw_uid) || (getuid () != pw->pw_uid) ||
+ (getegid () != pw->pw_gid) || (getgid () != pw->pw_gid))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Error becoming real+effective uid %d and gid %d: %m",
+ (int) pw->pw_uid, (int) pw->pw_gid);
+ goto out;
+ }
+
+ if (chdir (pw->pw_dir) != 0)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Error changing to home directory %s: %m",
+ pw->pw_dir);
+ goto out;
+ }
+
+
+ ret = TRUE;
+
+ out:
+ return ret;
+}
+
int
main (int argc,
char **argv)
}
}
+ error = NULL;
+ if (!become_user (POLKITD_USER, &error))
+ {
+ g_printerr ("Error switcing to user %s: %s\n",
+ POLKITD_USER, error->message);
+ g_clear_error (&error);
+ goto out;
+ }
+
+ g_print ("Successfully changed to user %s\n", POLKITD_USER);
+
+ if (g_getenv ("PATH") == NULL)
+ g_setenv ("PATH", "/usr/bin:/bin:/usr/sbin:/sbin", TRUE);
loop = g_main_loop_new (NULL, FALSE);