systemctl: automatically spawn temporary password agent when we might need one

This commit is contained in:
Lennart Poettering 2010-10-26 05:29:39 +02:00
parent 0ddf1d3aa5
commit 501fc174c2
3 changed files with 82 additions and 2 deletions

View file

@ -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

View file

@ -241,6 +241,29 @@
changes.</para></listitem>
</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>

View file

@ -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;