summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2010-10-26 05:29:39 +0200
committerLennart Poettering <lennart@poettering.net>2010-10-26 05:29:39 +0200
commit501fc174c22aebd3181af08a4cfa65cc92bbe233 (patch)
tree06b3d2d201cea6f6a28a06b1b556226052472dec
parent0ddf1d3aa5e96b752ad62be48f99d7850a3d8542 (diff)
systemctl: automatically spawn temporary password agent when we might need one
-rw-r--r--Makefile.am3
-rw-r--r--man/systemctl.xml23
-rw-r--r--src/systemctl.c58
3 files changed, 82 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am
index 7f8df05da7..b005f3aa67 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -53,9 +53,10 @@ AM_CPPFLAGS = \
-DSYSTEMD_BINARY_PATH=\"$(rootbindir)/systemd\" \
-DSYSTEMD_SHUTDOWN_BINARY_PATH=\"$(rootlibexecdir)/systemd-shutdown\" \
-DSYSTEMCTL_BINARY_PATH=\"$(rootbindir)/systemctl\" \
+ -DSYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH=\"$(rootbindir)/systemd-tty-ask-password-agent\" \
-DRUNTIME_DIR=\"$(localstatedir)/run\" \
-DRANDOM_SEED=\"$(localstatedir)/lib/random-seed\" \
- -DKEXEC_BINARY_PATH=\"$(rootsbindir)/kexec\" \
+ -DKEXEC_BINARY_PATH=\"/sbin/kexec\" \
-I $(top_srcdir)/src
if TARGET_GENTOO
diff --git a/man/systemctl.xml b/man/systemctl.xml
index cdf4f5cd29..10e0f82441 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -242,6 +242,29 @@
</varlistentry>
<varlistentry>
+ <term><option>--no-ask-password</option></term>
+
+ <listitem><para>When used with
+ <command>start</command> and related
+ commands, disables asking for
+ passwords. Background services may
+ require input of a password or
+ passphrase string, for example to
+ unlock system hard disks or
+ cryptographic certificates. Unless
+ this option is specified and the
+ command is invoked from a terminal
+ <command>systemctl</command> will
+ query the user on the terminal for the
+ necessary secrets. Use this option to
+ switch this behaviour off. In this
+ case the password must be supplied by
+ some other means (for example
+ graphical password agents) or the
+ service might fail.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--kill-mode=</option></term>
<listitem><para>When used with
diff --git a/src/systemctl.c b/src/systemctl.c
index ffbe4db541..a4b83afcf7 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -32,6 +32,7 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <stddef.h>
+#include <sys/prctl.h>
#include <dbus/dbus.h>
@@ -73,6 +74,7 @@ static bool arg_quiet = false;
static bool arg_full = false;
static bool arg_force = false;
static bool arg_defaults = false;
+static bool arg_ask_password = false;
static char **arg_wall = NULL;
static const char *arg_kill_who = NULL;
static const char *arg_kill_mode = NULL;
@@ -118,6 +120,47 @@ static bool on_tty(void) {
return t;
}
+static void spawn_ask_password_agent(void) {
+ pid_t parent, child;
+
+ /* We check STDIN here, not STDOUT, since this is about input,
+ * not output */
+ if (!isatty(STDIN_FILENO))
+ return;
+
+ if (!arg_ask_password)
+ return;
+
+ parent = getpid();
+
+ /* Spawns a temporary TTY agent, making sure it goes away when
+ * we go away */
+
+ if ((child = fork()) < 0)
+ return;
+
+ if (child == 0) {
+ /* In the child */
+
+ const char * const args[] = {
+ SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH,
+ "--watch",
+ NULL
+ };
+
+ if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
+ _exit(EXIT_FAILURE);
+
+ /* Check whether our parent died before we were able
+ * to set the death signal */
+ if (getppid() != parent)
+ _exit(EXIT_SUCCESS);
+
+ execv(args[0], (char **) args);
+ _exit(EXIT_FAILURE);
+ }
+}
+
static const char *ansi_highlight(bool b) {
if (!on_tty())
@@ -1269,6 +1312,8 @@ static int start_unit(DBusConnection *bus, char **args, unsigned n) {
assert(bus);
+ spawn_ask_password_agent();
+
if (arg_action == ACTION_SYSTEMCTL) {
method =
streq(args[0], "stop") ? "StopUnit" :
@@ -4010,6 +4055,8 @@ static int systemctl_help(void) {
" --global Enable/disable unit files globally\n"
" --no-reload When enabling/disabling unit files, don't reload daemon\n"
" configuration\n"
+ " --no-ask-password\n"
+ " Do not ask for system passwords\n"
" --kill-mode=MODE How to send signal\n"
" --kill-who=WHO Who to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n"
@@ -4146,7 +4193,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
ARG_NO_RELOAD,
ARG_DEFAULTS,
ARG_KILL_MODE,
- ARG_KILL_WHO
+ ARG_KILL_WHO,
+ ARG_NO_ASK_PASSWORD
};
static const struct option options[] = {
@@ -4171,6 +4219,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "kill-mode", required_argument, NULL, ARG_KILL_MODE },
{ "kill-who", required_argument, NULL, ARG_KILL_WHO },
{ "signal", required_argument, NULL, 's' },
+ { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{ NULL, 0, NULL, 0 }
};
@@ -4179,6 +4228,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
+ /* Only when running as systemctl we ask for passwords */
+ arg_ask_password = true;
+
while ((c = getopt_long(argc, argv, "ht:p:aqfs:", options, NULL)) >= 0) {
switch (c) {
@@ -4285,6 +4337,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
}
break;
+ case ARG_NO_ASK_PASSWORD:
+ arg_ask_password = false;
+ break;
+
case '?':
return -EINVAL;