From 8e0383cb9972f5b3b86e64f9b015f53671ce0323 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Fri, 25 May 2012 12:40:42 -0400 Subject: [PATCH] Run polkitd as an unprivileged user There's really no reason to run all this code as uid 0. Signed-off-by: David Zeuthen --- configure.ac | 25 +++++-- data/Makefile.am | 21 +++++- ...onf => org.freedesktop.PolicyKit1.conf.in} | 4 +- docs/man/polkit.xml | 17 ++++- docs/man/polkitd.xml | 6 ++ src/polkitbackend/Makefile.am | 4 +- src/polkitbackend/polkitd.c | 73 +++++++++++++++++++ 7 files changed, 136 insertions(+), 14 deletions(-) rename data/{org.freedesktop.PolicyKit1.conf => org.freedesktop.PolicyKit1.conf.in} (89%) diff --git a/configure.ac b/configure.ac index d9559cc..b26b333 100644 --- a/configure.ac +++ b/configure.ac @@ -193,6 +193,20 @@ if test "x$with_systemdsystemunitdir" != "xno"; then 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 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 --------------------------------------------------------------------------- @@ -496,7 +510,8 @@ echo " 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 " @@ -522,10 +537,10 @@ echo "NOTE: The file ${bindir}/pkexec must be owned by root and" 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 diff --git a/data/Makefile.am b/data/Makefile.am index 6623286..b2d0cde 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -4,6 +4,8 @@ NULL = 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) @@ -11,17 +13,28 @@ 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 @@ -32,16 +45,18 @@ $(systemdservice_DATA): $(systemdservice_in_files) Makefile @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) diff --git a/data/org.freedesktop.PolicyKit1.conf b/data/org.freedesktop.PolicyKit1.conf.in similarity index 89% rename from data/org.freedesktop.PolicyKit1.conf rename to data/org.freedesktop.PolicyKit1.conf.in index c8ef513..c749207 100644 --- a/data/org.freedesktop.PolicyKit1.conf +++ b/data/org.freedesktop.PolicyKit1.conf.in @@ -4,7 +4,7 @@ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> - + @@ -13,7 +13,7 @@ - + diff --git a/docs/man/polkit.xml b/docs/man/polkit.xml index bd39299..b19b92c 100644 --- a/docs/man/polkit.xml +++ b/docs/man/polkit.xml @@ -31,7 +31,16 @@ 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. + + + + The polkit authority is implemented as an system daemon, + polkitd8, + which itself has little privilege as it is running as the + polkitd system user. Mechanisms, subjects + and authentication agents communicate with the authority using + the system message bus. @@ -204,7 +213,7 @@ System Context | | DECLARING ACTIONS - A mechanism need to declare a set of ACTIONS in + A mechanism need to declare a set of actions 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 spawn() 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 polkitd system + user. diff --git a/docs/man/polkitd.xml b/docs/man/polkitd.xml index 879da2d..5fee8d4 100644 --- a/docs/man/polkitd.xml +++ b/docs/man/polkitd.xml @@ -40,6 +40,12 @@ whenever an application calls into the service. + + polkitd must be started with superuser + privileges but drops privileges early by switching to the + unprivileged polkitd system user. + + See the polkit8 diff --git a/src/polkitbackend/Makefile.am b/src/polkitbackend/Makefile.am index a173125..9f430d0 100644 --- a/src/polkitbackend/Makefile.am +++ b/src/polkitbackend/Makefile.am @@ -103,8 +103,10 @@ dist-hook : 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 diff --git a/src/polkitbackend/polkitd.c b/src/polkitbackend/polkitd.c index 0bb3f32..6a1bfb0 100644 --- a/src/polkitbackend/polkitd.c +++ b/src/polkitbackend/polkitd.c @@ -25,6 +25,9 @@ #include +#include +#include + #include #include @@ -94,6 +97,63 @@ on_sigint (gpointer user_data) 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) @@ -142,6 +202,19 @@ main (int argc, } } + 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); -- 2.34.1