771b4bc
From 8700830696b0db6b32358d89494e3463e83b745c Mon Sep 17 00:00:00 2001
771b4bc
From: Lennart Poettering <lennart@poettering.net>
771b4bc
Date: Wed, 11 Apr 2012 18:50:16 +0200
771b4bc
Subject: [PATCH] polkit: temporarily spawn of a polkit agent in terminals for
771b4bc
 possibly authenticated operations (cherry picked from
771b4bc
 commit 6bb92a169e8a65e7def5545798001e0dbecc7d4f)
771b4bc
771b4bc
Conflicts:
771b4bc
771b4bc
	Makefile.am
771b4bc
---
771b4bc
 Makefile.am                                        |   11 +-
771b4bc
 man/loginctl.xml                                   |    8 ++
771b4bc
 man/systemctl.xml                                  |   12 +-
771b4bc
 src/login/loginctl.c                               |   31 ++++-
771b4bc
 src/shared/util.c                                  |   85 ++++++++++++++
771b4bc
 src/shared/util.h                                  |    3 +
771b4bc
 src/spawn-agent.c                                  |  120 --------------------
771b4bc
 src/spawn-ask-password-agent.c                     |   64 +++++++++++
771b4bc
 .../spawn-agent.h => spawn-ask-password-agent.h}   |    8 +-
771b4bc
 src/spawn-polkit-agent.c                           |   64 +++++++++++
771b4bc
 src/spawn-polkit-agent.h                           |   28 +++++
771b4bc
 src/systemctl.c                                    |   32 ++++--
771b4bc
 12 files changed, 322 insertions(+), 144 deletions(-)
771b4bc
 delete mode 100644 src/spawn-agent.c
771b4bc
 create mode 100644 src/spawn-ask-password-agent.c
771b4bc
 rename src/{core/spawn-agent.h => spawn-ask-password-agent.h} (84%)
771b4bc
 create mode 100644 src/spawn-polkit-agent.c
771b4bc
 create mode 100644 src/spawn-polkit-agent.h
771b4bc
771b4bc
diff --git a/Makefile.am b/Makefile.am
771b4bc
index 23ca11a..abe2e7f 100644
771b4bc
--- a/Makefile.am
771b4bc
+++ b/Makefile.am
771b4bc
@@ -101,6 +101,7 @@ AM_CPPFLAGS = \
771b4bc
 	-DSYSTEM_SHUTDOWN_PATH=\"$(systemshutdowndir)\" \
771b4bc
 	-DSYSTEMD_KBD_MODEL_MAP=\"$(pkgdatadir)/kbd-model-map\" \
771b4bc
         -DX_SERVER=\"$(bindir)/X\" \
771b4bc
+        -DPOLKIT_AGENT_BINARY_PATH=\"$(bindir)/pkttyagent\" \
771b4bc
 	-I $(top_srcdir)/src \
771b4bc
 	-I $(top_srcdir)/src/shared \
771b4bc
 	-I $(top_srcdir)/src/readahead \
771b4bc
@@ -755,8 +756,7 @@ libsystemd_core_la_SOURCES = \
771b4bc
 	src/core/ask-password-api.h \
771b4bc
 	src/core/sysfs-show.h \
771b4bc
 	src/core/polkit.h \
771b4bc
-	src/core/dbus-loop.h \
771b4bc
-	src/core/spawn-agent.h
771b4bc
+	src/core/dbus-loop.h
771b4bc
 
771b4bc
 nodist_libsystemd_core_la_SOURCES = \
771b4bc
 	src/load-fragment-gperf.c \
771b4bc
@@ -1078,7 +1078,10 @@ systemctl_SOURCES = \
771b4bc
 	src/cgroup-show.h \
771b4bc
 	src/unit-name.c \
771b4bc
 	src/install.c \
771b4bc
-	src/spawn-agent.c \
771b4bc
+	src/spawn-ask-password-agent.c \
771b4bc
+	src/spawn-ask-password-agent.h \
771b4bc
+	src/spawn-polkit-agent.c \
771b4bc
+	src/spawn-polkit-agent.h \
771b4bc
 	src/logs-show.c \
771b4bc
 	src/logs-show.h
771b4bc
 
771b4bc
@@ -2015,6 +2018,8 @@ loginctl_SOURCES = \
771b4bc
 	src/login/loginctl.c \
771b4bc
 	src/login/sysfs-show.c \
771b4bc
 	src/dbus-common.c \
771b4bc
+	src/spawn-polkit-agent.c \
771b4bc
+	src/spawn-polkit-agent.h \
771b4bc
 	src/cgroup-show.c \
771b4bc
 	src/cgroup-show.h
771b4bc
 
771b4bc
diff --git a/man/loginctl.xml b/man/loginctl.xml
771b4bc
index be72cc3..7cfb194 100644
771b4bc
--- a/man/loginctl.xml
771b4bc
+++ b/man/loginctl.xml
771b4bc
@@ -120,6 +120,14 @@
771b4bc
 			</varlistentry>
771b4bc
 
771b4bc
                         <varlistentry>
771b4bc
+                                <term><option>--no-ask-password</option></term>
771b4bc
+
771b4bc
+                                <listitem><para>Don't query the user
771b4bc
+                                for authentication for privileged
771b4bc
+                                operations.</para></listitem>
771b4bc
+                        </varlistentry>
771b4bc
+
771b4bc
+                        <varlistentry>
771b4bc
                                 <term><option>--kill-who=</option></term>
771b4bc
 
771b4bc
                                 <listitem><para>When used with
771b4bc
diff --git a/man/systemctl.xml b/man/systemctl.xml
771b4bc
index ffe0164..97280fd 100644
771b4bc
--- a/man/systemctl.xml
771b4bc
+++ b/man/systemctl.xml
771b4bc
@@ -300,11 +300,13 @@
771b4bc
                                 <command>systemctl</command> will
771b4bc
                                 query the user on the terminal for the
771b4bc
                                 necessary secrets. Use this option to
771b4bc
-                                switch this behavior off. In this
771b4bc
-                                case the password must be supplied by
771b4bc
-                                some other means (for example
771b4bc
-                                graphical password agents) or the
771b4bc
-                                service might fail.</para></listitem>
771b4bc
+                                switch this behavior off. In this case
771b4bc
+                                the password must be supplied by some
771b4bc
+                                other means (for example graphical
771b4bc
+                                password agents) or the service might
771b4bc
+                                fail. This also disables querying the
771b4bc
+                                user for authentication for privileged
771b4bc
+                                operations.</para></listitem>
771b4bc
                         </varlistentry>
771b4bc
 
771b4bc
                         <varlistentry>
771b4bc
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
771b4bc
index 30e97e3..2633b47 100644
771b4bc
--- a/src/login/loginctl.c
771b4bc
+++ b/src/login/loginctl.c
771b4bc
@@ -35,6 +35,7 @@
771b4bc
 #include "strv.h"
771b4bc
 #include "cgroup-show.h"
771b4bc
 #include "sysfs-show.h"
771b4bc
+#include "spawn-polkit-agent.h"
771b4bc
 
771b4bc
 static char **arg_property = NULL;
771b4bc
 static bool arg_all = false;
771b4bc
@@ -46,6 +47,7 @@ static enum transport {
771b4bc
         TRANSPORT_SSH,
771b4bc
         TRANSPORT_POLKIT
771b4bc
 } arg_transport = TRANSPORT_NORMAL;
771b4bc
+static bool arg_ask_password = true;
771b4bc
 static const char *arg_host = NULL;
771b4bc
 
771b4bc
 static bool on_tty(void) {
771b4bc
@@ -68,8 +70,20 @@ static void pager_open_if_enabled(void) {
771b4bc
         /* Cache result before we open the pager */
771b4bc
         on_tty();
771b4bc
 
771b4bc
-        if (!arg_no_pager)
771b4bc
-                pager_open();
771b4bc
+        if (arg_no_pager)
771b4bc
+                return;
771b4bc
+
771b4bc
+        pager_open();
771b4bc
+}
771b4bc
+
771b4bc
+static void polkit_agent_open_if_enabled(void) {
771b4bc
+
771b4bc
+        /* Open the polkit agent as a child process if necessary */
771b4bc
+
771b4bc
+        if (!arg_ask_password)
771b4bc
+                return;
771b4bc
+
771b4bc
+        polkit_agent_open();
771b4bc
 }
771b4bc
 
771b4bc
 static int list_sessions(DBusConnection *bus, char **args, unsigned n) {
771b4bc
@@ -1286,6 +1300,8 @@ static int enable_linger(DBusConnection *bus, char **args, unsigned n) {
771b4bc
 
771b4bc
         dbus_error_init(&error);
771b4bc
 
771b4bc
+        polkit_agent_open_if_enabled();
771b4bc
+
771b4bc
         b = streq(args[0], "enable-linger");
771b4bc
 
771b4bc
         for (i = 1; i < n; i++) {
771b4bc
@@ -1490,6 +1506,8 @@ static int attach(DBusConnection *bus, char **args, unsigned n) {
771b4bc
 
771b4bc
         dbus_error_init(&error);
771b4bc
 
771b4bc
+        polkit_agent_open_if_enabled();
771b4bc
+
771b4bc
         for (i = 2; i < n; i++) {
771b4bc
                 DBusMessage *reply;
771b4bc
 
771b4bc
@@ -1546,6 +1564,8 @@ static int flush_devices(DBusConnection *bus, char **args, unsigned n) {
771b4bc
 
771b4bc
         dbus_error_init(&error);
771b4bc
 
771b4bc
+        polkit_agent_open_if_enabled();
771b4bc
+
771b4bc
         m = dbus_message_new_method_call(
771b4bc
                         "org.freedesktop.login1",
771b4bc
                         "/org/freedesktop/login1",
771b4bc
@@ -1684,7 +1704,8 @@ static int parse_argv(int argc, char *argv[]) {
771b4bc
         enum {
771b4bc
                 ARG_VERSION = 0x100,
771b4bc
                 ARG_NO_PAGER,
771b4bc
-                ARG_KILL_WHO
771b4bc
+                ARG_KILL_WHO,
771b4bc
+                ARG_NO_ASK_PASSWORD
771b4bc
         };
771b4bc
 
771b4bc
         static const struct option options[] = {
771b4bc
@@ -1697,6 +1718,7 @@ static int parse_argv(int argc, char *argv[]) {
771b4bc
                 { "signal",    required_argument, NULL, 's'           },
771b4bc
                 { "host",      required_argument, NULL, 'H'           },
771b4bc
                 { "privileged",no_argument,       NULL, 'P'           },
771b4bc
+                { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
771b4bc
                 { NULL,        0,                 NULL, 0             }
771b4bc
         };
771b4bc
 
771b4bc
@@ -1744,6 +1766,9 @@ static int parse_argv(int argc, char *argv[]) {
771b4bc
                         arg_no_pager = true;
771b4bc
                         break;
771b4bc
 
771b4bc
+                case ARG_NO_ASK_PASSWORD:
771b4bc
+                        arg_ask_password = false;
771b4bc
+
771b4bc
                 case ARG_KILL_WHO:
771b4bc
                         arg_kill_who = optarg;
771b4bc
                         break;
771b4bc
diff --git a/src/shared/util.c b/src/shared/util.c
771b4bc
index 73e0a29..7f41fc4 100644
771b4bc
--- a/src/shared/util.c
771b4bc
+++ b/src/shared/util.c
771b4bc
@@ -6035,3 +6035,88 @@ int fd_inc_rcvbuf(int fd, size_t n) {
771b4bc
 
771b4bc
         return 1;
771b4bc
 }
771b4bc
+
771b4bc
+int fork_agent(pid_t *pid, const char *path, ...) {
771b4bc
+        pid_t parent_pid, agent_pid;
771b4bc
+        int fd;
771b4bc
+        bool stdout_is_tty, stderr_is_tty;
771b4bc
+        unsigned n, i;
771b4bc
+        va_list ap;
771b4bc
+        char **l;
771b4bc
+
771b4bc
+        assert(pid);
771b4bc
+        assert(path);
771b4bc
+
771b4bc
+        parent_pid = getpid();
771b4bc
+
771b4bc
+        /* Spawns a temporary TTY agent, making sure it goes away when
771b4bc
+         * we go away */
771b4bc
+
771b4bc
+        agent_pid = fork();
771b4bc
+        if (agent_pid < 0)
771b4bc
+                return -errno;
771b4bc
+
771b4bc
+        if (agent_pid != 0) {
771b4bc
+                *pid = agent_pid;
771b4bc
+                return 0;
771b4bc
+        }
771b4bc
+
771b4bc
+        /* In the child:
771b4bc
+         *
771b4bc
+         * Make sure the agent goes away when the parent dies */
771b4bc
+        if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
771b4bc
+                _exit(EXIT_FAILURE);
771b4bc
+
771b4bc
+        /* Check whether our parent died before we were able
771b4bc
+         * to set the death signal */
771b4bc
+        if (getppid() != parent_pid)
771b4bc
+                _exit(EXIT_SUCCESS);
771b4bc
+
771b4bc
+        /* Don't leak fds to the agent */
771b4bc
+        close_all_fds(NULL, 0);
771b4bc
+
771b4bc
+        stdout_is_tty = isatty(STDOUT_FILENO);
771b4bc
+        stderr_is_tty = isatty(STDERR_FILENO);
771b4bc
+
771b4bc
+        if (!stdout_is_tty || !stderr_is_tty) {
771b4bc
+                /* Detach from stdout/stderr. and reopen
771b4bc
+                 * /dev/tty for them. This is important to
771b4bc
+                 * ensure that when systemctl is started via
771b4bc
+                 * popen() or a similar call that expects to
771b4bc
+                 * read EOF we actually do generate EOF and
771b4bc
+                 * not delay this indefinitely by because we
771b4bc
+                 * keep an unused copy of stdin around. */
771b4bc
+                fd = open("/dev/tty", O_WRONLY);
771b4bc
+                if (fd < 0) {
771b4bc
+                        log_error("Failed to open /dev/tty: %m");
771b4bc
+                        _exit(EXIT_FAILURE);
771b4bc
+                }
771b4bc
+
771b4bc
+                if (!stdout_is_tty)
771b4bc
+                        dup2(fd, STDOUT_FILENO);
771b4bc
+
771b4bc
+                if (!stderr_is_tty)
771b4bc
+                        dup2(fd, STDERR_FILENO);
771b4bc
+
771b4bc
+                if (fd > 2)
771b4bc
+                        close(fd);
771b4bc
+        }
771b4bc
+
771b4bc
+        /* Count arguments */
771b4bc
+        va_start(ap, path);
771b4bc
+        for (n = 0; va_arg(ap, char*); n++)
771b4bc
+                ;
771b4bc
+        va_end(ap);
771b4bc
+
771b4bc
+        /* Allocate strv */
771b4bc
+        l = alloca(sizeof(char *) * (n + 1));
771b4bc
+
771b4bc
+        /* Fill in arguments */
771b4bc
+        va_start(ap, path);
771b4bc
+        for (i = 0; i <= n; i++)
771b4bc
+                l[i] = va_arg(ap, char*);
771b4bc
+        va_end(ap);
771b4bc
+
771b4bc
+        execv(path, l);
771b4bc
+        _exit(EXIT_FAILURE);
771b4bc
+}
771b4bc
diff --git a/src/shared/util.h b/src/shared/util.h
771b4bc
index e0934e5..5e927df 100644
771b4bc
--- a/src/shared/util.h
771b4bc
+++ b/src/shared/util.h
771b4bc
@@ -528,4 +528,7 @@ int is_kernel_thread(pid_t pid);
771b4bc
 
771b4bc
 int fd_inc_sndbuf(int fd, size_t n);
771b4bc
 int fd_inc_rcvbuf(int fd, size_t n);
771b4bc
+
771b4bc
+int fork_agent(pid_t *pid, const char *path, ...);
771b4bc
+
771b4bc
 #endif
771b4bc
diff --git a/src/spawn-agent.c b/src/spawn-agent.c
771b4bc
deleted file mode 100644
771b4bc
index 2de2530..0000000
771b4bc
--- a/src/spawn-agent.c
771b4bc
+++ /dev/null
771b4bc
@@ -1,120 +0,0 @@
771b4bc
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
771b4bc
-
771b4bc
-/***
771b4bc
-  This file is part of systemd.
771b4bc
-
771b4bc
-  Copyright 2011 Lennart Poettering
771b4bc
-
771b4bc
-  systemd is free software; you can redistribute it and/or modify it
771b4bc
-  under the terms of the GNU General Public License as published by
771b4bc
-  the Free Software Foundation; either version 2 of the License, or
771b4bc
-  (at your option) any later version.
771b4bc
-
771b4bc
-  systemd is distributed in the hope that it will be useful, but
771b4bc
-  WITHOUT ANY WARRANTY; without even the implied warranty of
771b4bc
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
771b4bc
-  General Public License for more details.
771b4bc
-
771b4bc
-  You should have received a copy of the GNU General Public License
771b4bc
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
771b4bc
-***/
771b4bc
-
771b4bc
-#include <sys/types.h>
771b4bc
-#include <stdlib.h>
771b4bc
-#include <unistd.h>
771b4bc
-#include <string.h>
771b4bc
-#include <sys/prctl.h>
771b4bc
-#include <signal.h>
771b4bc
-#include <fcntl.h>
771b4bc
-
771b4bc
-#include "log.h"
771b4bc
-#include "util.h"
771b4bc
-#include "spawn-agent.h"
771b4bc
-
771b4bc
-static pid_t agent_pid = 0;
771b4bc
-
771b4bc
-void agent_open(void) {
771b4bc
-        pid_t parent_pid;
771b4bc
-
771b4bc
-        if (agent_pid > 0)
771b4bc
-                return;
771b4bc
-
771b4bc
-        /* We check STDIN here, not STDOUT, since this is about input,
771b4bc
-         * not output */
771b4bc
-        if (!isatty(STDIN_FILENO))
771b4bc
-                return;
771b4bc
-
771b4bc
-        parent_pid = getpid();
771b4bc
-
771b4bc
-        /* Spawns a temporary TTY agent, making sure it goes away when
771b4bc
-         * we go away */
771b4bc
-
771b4bc
-        agent_pid = fork();
771b4bc
-        if (agent_pid < 0) {
771b4bc
-                log_error("Failed to fork agent: %m");
771b4bc
-                return;
771b4bc
-        }
771b4bc
-
771b4bc
-        if (agent_pid == 0) {
771b4bc
-                /* In the child */
771b4bc
-
771b4bc
-                int fd;
771b4bc
-                bool stdout_is_tty, stderr_is_tty;
771b4bc
-
771b4bc
-                /* Make sure the agent goes away when the parent dies */
771b4bc
-                if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
771b4bc
-                        _exit(EXIT_FAILURE);
771b4bc
-
771b4bc
-                /* Check whether our parent died before we were able
771b4bc
-                 * to set the death signal */
771b4bc
-                if (getppid() != parent_pid)
771b4bc
-                        _exit(EXIT_SUCCESS);
771b4bc
-
771b4bc
-                /* Don't leak fds to the agent */
771b4bc
-                close_all_fds(NULL, 0);
771b4bc
-
771b4bc
-                stdout_is_tty = isatty(STDOUT_FILENO);
771b4bc
-                stderr_is_tty = isatty(STDERR_FILENO);
771b4bc
-
771b4bc
-                if (!stdout_is_tty || !stderr_is_tty) {
771b4bc
-                        /* Detach from stdout/stderr. and reopen
771b4bc
-                         * /dev/tty for them. This is important to
771b4bc
-                         * ensure that when systemctl is started via
771b4bc
-                         * popen() or a similar call that expects to
771b4bc
-                         * read EOF we actually do generate EOF and
771b4bc
-                         * not delay this indefinitely by because we
771b4bc
-                         * keep an unused copy of stdin around. */
771b4bc
-                        fd = open("/dev/tty", O_WRONLY);
771b4bc
-                        if (fd < 0) {
771b4bc
-                                log_error("Failed to open /dev/tty: %m");
771b4bc
-                                _exit(EXIT_FAILURE);
771b4bc
-                        }
771b4bc
-
771b4bc
-                        if (!stdout_is_tty)
771b4bc
-                                dup2(fd, STDOUT_FILENO);
771b4bc
-
771b4bc
-                        if (!stderr_is_tty)
771b4bc
-                                dup2(fd, STDERR_FILENO);
771b4bc
-
771b4bc
-                        if (fd > 2)
771b4bc
-                                close(fd);
771b4bc
-                }
771b4bc
-
771b4bc
-                execl(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL);
771b4bc
-
771b4bc
-                log_error("Unable to execute agent: %m");
771b4bc
-                _exit(EXIT_FAILURE);
771b4bc
-        }
771b4bc
-}
771b4bc
-
771b4bc
-void agent_close(void) {
771b4bc
-
771b4bc
-        if (agent_pid <= 0)
771b4bc
-                return;
771b4bc
-
771b4bc
-        /* Inform agent that we are done */
771b4bc
-        kill(agent_pid, SIGTERM);
771b4bc
-        kill(agent_pid, SIGCONT);
771b4bc
-        wait_for_terminate(agent_pid, NULL);
771b4bc
-        agent_pid = 0;
771b4bc
-}
771b4bc
diff --git a/src/spawn-ask-password-agent.c b/src/spawn-ask-password-agent.c
771b4bc
new file mode 100644
771b4bc
index 0000000..82db08c
771b4bc
--- /dev/null
771b4bc
+++ b/src/spawn-ask-password-agent.c
771b4bc
@@ -0,0 +1,64 @@
771b4bc
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
771b4bc
+
771b4bc
+/***
771b4bc
+  This file is part of systemd.
771b4bc
+
771b4bc
+  Copyright 2011 Lennart Poettering
771b4bc
+
771b4bc
+  systemd is free software; you can redistribute it and/or modify it
771b4bc
+  under the terms of the GNU General Public License as published by
771b4bc
+  the Free Software Foundation; either version 2 of the License, or
771b4bc
+  (at your option) any later version.
771b4bc
+
771b4bc
+  systemd is distributed in the hope that it will be useful, but
771b4bc
+  WITHOUT ANY WARRANTY; without even the implied warranty of
771b4bc
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
771b4bc
+  General Public License for more details.
771b4bc
+
771b4bc
+  You should have received a copy of the GNU General Public License
771b4bc
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
771b4bc
+***/
771b4bc
+
771b4bc
+#include <sys/types.h>
771b4bc
+#include <stdlib.h>
771b4bc
+#include <unistd.h>
771b4bc
+#include <string.h>
771b4bc
+#include <sys/prctl.h>
771b4bc
+#include <signal.h>
771b4bc
+#include <fcntl.h>
771b4bc
+
771b4bc
+#include "log.h"
771b4bc
+#include "util.h"
771b4bc
+#include "spawn-ask-password-agent.h"
771b4bc
+
771b4bc
+static pid_t agent_pid = 0;
771b4bc
+
771b4bc
+int ask_password_agent_open(void) {
771b4bc
+        int r;
771b4bc
+
771b4bc
+        if (agent_pid > 0)
771b4bc
+                return 0;
771b4bc
+
771b4bc
+        /* We check STDIN here, not STDOUT, since this is about input,
771b4bc
+         * not output */
771b4bc
+        if (!isatty(STDIN_FILENO))
771b4bc
+                return 0;
771b4bc
+
771b4bc
+        r = fork_agent(&agent_pid, SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL);
771b4bc
+        if (r < 0)
771b4bc
+                log_error("Failed to fork TTY ask password agent: %s", strerror(-r));
771b4bc
+
771b4bc
+        return r;
771b4bc
+}
771b4bc
+
771b4bc
+void ask_password_agent_close(void) {
771b4bc
+
771b4bc
+        if (agent_pid <= 0)
771b4bc
+                return;
771b4bc
+
771b4bc
+        /* Inform agent that we are done */
771b4bc
+        kill(agent_pid, SIGTERM);
771b4bc
+        kill(agent_pid, SIGCONT);
771b4bc
+        wait_for_terminate(agent_pid, NULL);
771b4bc
+        agent_pid = 0;
771b4bc
+}
771b4bc
diff --git a/src/core/spawn-agent.h b/src/spawn-ask-password-agent.h
771b4bc
similarity index 84%
771b4bc
rename from src/core/spawn-agent.h
771b4bc
rename to src/spawn-ask-password-agent.h
771b4bc
index fd0a910..dae039a 100644
771b4bc
--- a/src/core/spawn-agent.h
771b4bc
+++ b/src/spawn-ask-password-agent.h
771b4bc
@@ -1,7 +1,7 @@
771b4bc
 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
771b4bc
 
771b4bc
-#ifndef foospawnagenthfoo
771b4bc
-#define foospawnagenthfoo
771b4bc
+#ifndef foospawnaskpasswordagenthfoo
771b4bc
+#define foospawnaskpasswordagenthfoo
771b4bc
 
771b4bc
 /***
771b4bc
   This file is part of systemd.
771b4bc
@@ -22,7 +22,7 @@
771b4bc
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
771b4bc
 ***/
771b4bc
 
771b4bc
-void agent_open(void);
771b4bc
-void agent_close(void);
771b4bc
+int ask_password_agent_open(void);
771b4bc
+void ask_password_agent_close(void);
771b4bc
 
771b4bc
 #endif
771b4bc
diff --git a/src/spawn-polkit-agent.c b/src/spawn-polkit-agent.c
771b4bc
new file mode 100644
771b4bc
index 0000000..0da9abb
771b4bc
--- /dev/null
771b4bc
+++ b/src/spawn-polkit-agent.c
771b4bc
@@ -0,0 +1,64 @@
771b4bc
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
771b4bc
+
771b4bc
+/***
771b4bc
+  This file is part of systemd.
771b4bc
+
771b4bc
+  Copyright 2011 Lennart Poettering
771b4bc
+
771b4bc
+  systemd is free software; you can redistribute it and/or modify it
771b4bc
+  under the terms of the GNU General Public License as published by
771b4bc
+  the Free Software Foundation; either version 2 of the License, or
771b4bc
+  (at your option) any later version.
771b4bc
+
771b4bc
+  systemd is distributed in the hope that it will be useful, but
771b4bc
+  WITHOUT ANY WARRANTY; without even the implied warranty of
771b4bc
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
771b4bc
+  General Public License for more details.
771b4bc
+
771b4bc
+  You should have received a copy of the GNU General Public License
771b4bc
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
771b4bc
+***/
771b4bc
+
771b4bc
+#include <sys/types.h>
771b4bc
+#include <stdlib.h>
771b4bc
+#include <unistd.h>
771b4bc
+#include <string.h>
771b4bc
+#include <sys/prctl.h>
771b4bc
+#include <signal.h>
771b4bc
+#include <fcntl.h>
771b4bc
+
771b4bc
+#include "log.h"
771b4bc
+#include "util.h"
771b4bc
+#include "spawn-polkit-agent.h"
771b4bc
+
771b4bc
+static pid_t agent_pid = 0;
771b4bc
+
771b4bc
+int polkit_agent_open(void) {
771b4bc
+        int r;
771b4bc
+
771b4bc
+        if (agent_pid > 0)
771b4bc
+                return 0;
771b4bc
+
771b4bc
+        /* We check STDIN here, not STDOUT, since this is about input,
771b4bc
+         * not output */
771b4bc
+        if (!isatty(STDIN_FILENO))
771b4bc
+                return 0;
771b4bc
+
771b4bc
+        r = fork_agent(&agent_pid, POLKIT_AGENT_BINARY_PATH, POLKIT_AGENT_BINARY_PATH, NULL);
771b4bc
+        if (r < 0)
771b4bc
+                log_error("Failed to fork TTY ask password agent: %s", strerror(-r));
771b4bc
+
771b4bc
+        return r;
771b4bc
+}
771b4bc
+
771b4bc
+void polkit_agent_close(void) {
771b4bc
+
771b4bc
+        if (agent_pid <= 0)
771b4bc
+                return;
771b4bc
+
771b4bc
+        /* Inform agent that we are done */
771b4bc
+        kill(agent_pid, SIGTERM);
771b4bc
+        kill(agent_pid, SIGCONT);
771b4bc
+        wait_for_terminate(agent_pid, NULL);
771b4bc
+        agent_pid = 0;
771b4bc
+}
771b4bc
diff --git a/src/spawn-polkit-agent.h b/src/spawn-polkit-agent.h
771b4bc
new file mode 100644
771b4bc
index 0000000..34131f0
771b4bc
--- /dev/null
771b4bc
+++ b/src/spawn-polkit-agent.h
771b4bc
@@ -0,0 +1,28 @@
771b4bc
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
771b4bc
+
771b4bc
+#ifndef foospawnpolkitagenthfoo
771b4bc
+#define foospawnpolkitagenthfoo
771b4bc
+
771b4bc
+/***
771b4bc
+  This file is part of systemd.
771b4bc
+
771b4bc
+  Copyright 2012 Lennart Poettering
771b4bc
+
771b4bc
+  systemd is free software; you can redistribute it and/or modify it
771b4bc
+  under the terms of the GNU General Public License as published by
771b4bc
+  the Free Software Foundation; either version 2 of the License, or
771b4bc
+  (at your option) any later version.
771b4bc
+
771b4bc
+  systemd is distributed in the hope that it will be useful, but
771b4bc
+  WITHOUT ANY WARRANTY; without even the implied warranty of
771b4bc
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
771b4bc
+  General Public License for more details.
771b4bc
+
771b4bc
+  You should have received a copy of the GNU General Public License
771b4bc
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
771b4bc
+***/
771b4bc
+
771b4bc
+int polkit_agent_open(void);
771b4bc
+void polkit_agent_close(void);
771b4bc
+
771b4bc
+#endif
771b4bc
diff --git a/src/systemctl.c b/src/systemctl.c
771b4bc
index 43a1446..7abd928 100644
771b4bc
--- a/src/systemctl.c
771b4bc
+++ b/src/systemctl.c
771b4bc
@@ -57,7 +57,8 @@
771b4bc
 #include "build.h"
771b4bc
 #include "unit-name.h"
771b4bc
 #include "pager.h"
771b4bc
-#include "spawn-agent.h"
771b4bc
+#include "spawn-ask-password-agent.h"
771b4bc
+#include "spawn-polkit-agent.h"
771b4bc
 #include "install.h"
771b4bc
 #include "logs-show.h"
771b4bc
 
771b4bc
@@ -78,7 +79,7 @@ static bool arg_dry = false;
771b4bc
 static bool arg_quiet = false;
771b4bc
 static bool arg_full = false;
771b4bc
 static int arg_force = 0;
771b4bc
-static bool arg_ask_password = false;
771b4bc
+static bool arg_ask_password = true;
771b4bc
 static bool arg_failed = false;
771b4bc
 static bool arg_runtime = false;
771b4bc
 static char **arg_wall = NULL;
771b4bc
@@ -154,7 +155,7 @@ static void pager_open_if_enabled(void) {
771b4bc
         pager_open();
771b4bc
 }
771b4bc
 
771b4bc
-static void agent_open_if_enabled(void) {
771b4bc
+static void ask_password_agent_open_if_enabled(void) {
771b4bc
 
771b4bc
         /* Open the password agent as a child process if necessary */
771b4bc
 
771b4bc
@@ -164,7 +165,20 @@ static void agent_open_if_enabled(void) {
771b4bc
         if (arg_scope != UNIT_FILE_SYSTEM)
771b4bc
                 return;
771b4bc
 
771b4bc
-        agent_open();
771b4bc
+        ask_password_agent_open();
771b4bc
+}
771b4bc
+
771b4bc
+static void polkit_agent_open_if_enabled(void) {
771b4bc
+
771b4bc
+        /* Open the polkit agent as a child process if necessary */
771b4bc
+
771b4bc
+        if (!arg_ask_password)
771b4bc
+                return;
771b4bc
+
771b4bc
+        if (arg_scope != UNIT_FILE_SYSTEM)
771b4bc
+                return;
771b4bc
+
771b4bc
+        polkit_agent_open();
771b4bc
 }
771b4bc
 
771b4bc
 static const char *ansi_highlight_red(bool b) {
771b4bc
@@ -1601,7 +1615,7 @@ static int start_unit(DBusConnection *bus, char **args) {
771b4bc
 
771b4bc
         assert(bus);
771b4bc
 
771b4bc
-        agent_open_if_enabled();
771b4bc
+        ask_password_agent_open_if_enabled();
771b4bc
 
771b4bc
         if (arg_action == ACTION_SYSTEMCTL) {
771b4bc
                 method =
771b4bc
@@ -1695,6 +1709,8 @@ static int reboot_with_logind(DBusConnection *bus, enum action a) {
771b4bc
 
771b4bc
         dbus_error_init(&error);
771b4bc
 
771b4bc
+        polkit_agent_open_if_enabled();
771b4bc
+
771b4bc
         switch (a) {
771b4bc
 
771b4bc
         case ACTION_REBOOT:
771b4bc
@@ -4290,9 +4306,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
771b4bc
         assert(argc >= 0);
771b4bc
         assert(argv);
771b4bc
 
771b4bc
-        /* Only when running as systemctl we ask for passwords */
771b4bc
-        arg_ask_password = true;
771b4bc
-
771b4bc
         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
771b4bc
 
771b4bc
                 switch (c) {
771b4bc
@@ -5503,7 +5516,8 @@ finish:
771b4bc
         strv_free(arg_property);
771b4bc
 
771b4bc
         pager_close();
771b4bc
-        agent_close();
771b4bc
+        ask_password_agent_close();
771b4bc
+        polkit_agent_close();
771b4bc
 
771b4bc
         return retval;
771b4bc
 }