From 501fc174c22aebd3181af08a4cfa65cc92bbe233 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Oct 2010 05:29:39 +0200 Subject: [PATCH] systemctl: automatically spawn temporary password agent when we might need one --- Makefile.am | 3 ++- man/systemctl.xml | 23 +++++++++++++++++++ src/systemctl.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 7f8df05da..b005f3aa6 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 cdf4f5cd2..10e0f8244 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -241,6 +241,29 @@ changes. + + + + When used with + start 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 + systemctl 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. + + diff --git a/src/systemctl.c b/src/systemctl.c index ffbe4db54..a4b83afcf 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -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; -- 2.30.2