Compare commits
16 Commits
2717291b2e
...
f312393499
Author | SHA1 | Date |
---|---|---|
Lennart Poettering | f312393499 | |
Antonio Alvarez Feijoo | bf39626d61 | |
Marius Hoch | ff831e7c50 | |
Lennart Poettering | 92e38817d0 | |
Lennart Poettering | c6ffcaa82e | |
Lennart Poettering | 510480a1ca | |
Lennart Poettering | db3d573e3a | |
Lennart Poettering | 476117a71d | |
Lennart Poettering | 8500234805 | |
Lennart Poettering | 9a92548dc5 | |
Daan De Meyer | 81af8f998e | |
chenjiayi | 4fc8a63f9e | |
Jason Yundt | dfb3155419 | |
Daan De Meyer | fc5037e7d7 | |
Yu Watanabe | 13f6ec7ce7 | |
Yu Watanabe | 6e1816ef16 |
|
@ -7,25 +7,30 @@ SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
|
||||||
# Password Agents
|
# Password Agents
|
||||||
|
|
||||||
systemd 12 and newer support lightweight password agents which can be used to query the user for system-level passwords or passphrases.
|
systemd 12 and newer support lightweight password agents which can be used to
|
||||||
These are passphrases that are not related to a specific user, but to some kind of hardware or service.
|
query the user for system-level passwords or passphrases. These are
|
||||||
Right now this is used exclusively for encrypted hard-disk passphrases but later on this is likely to be used to query passphrases of SSL certificates at Apache startup time as well.
|
passphrases that are not related to a specific user, but to some kind of
|
||||||
The basic idea is that a system component requesting a password entry can simply drop a simple .ini-style file into `/run/systemd/ask-password` which multiple different agents may watch via `inotify()`, and query the user as necessary.
|
hardware or service. This is used for encrypted hard-disk passphrases or to
|
||||||
The answer is then sent back to the querier via an `AF_UNIX`/`SOCK_DGRAM` socket.
|
query passphrases of SSL certificates at web server start-up time. The basic
|
||||||
Multiple agents might be running at the same time in which case they all should query the user and the agent which answers first wins.
|
idea is that a system component requesting a password entry can simply drop a
|
||||||
Right now systemd ships with the following passphrase agents:
|
simple .ini-style file into `/run/systemd/ask-password/` which multiple
|
||||||
|
different agents may watch via `inotify()`, and query the user as necessary.
|
||||||
|
The answer is then sent back to the querier via an `AF_UNIX`/`SOCK_DGRAM`
|
||||||
|
socket. Multiple agents might be running at the same time in which case they
|
||||||
|
all should query the user and the agent which answers first wins. Right now
|
||||||
|
systemd ships with the following passphrase agents:
|
||||||
|
|
||||||
* A Plymouth agent used for querying passwords during boot-up
|
* A Plymouth agent used for querying passwords during boot-up
|
||||||
* A console agent used in similar situations if Plymouth is not available
|
* A console agent used in similar situations if Plymouth is not available
|
||||||
* A GNOME agent which can be run as part of the normal user session which pops up a notification message and icon which when clicked receives the passphrase from the user.
|
|
||||||
This is useful and necessary in case an encrypted system hard-disk is plugged in when the machine is already up.
|
|
||||||
* A [`wall(1)`](https://man7.org/linux/man-pages/man1/wall.1.html) agent which sends wall messages as soon as a password shall be entered.
|
* A [`wall(1)`](https://man7.org/linux/man-pages/man1/wall.1.html) agent which sends wall messages as soon as a password shall be entered.
|
||||||
* A simple tty agent which is built into "`systemctl start`" (and similar commands) and asks passwords to the user during manual startup of a service
|
* A simple tty agent which is built into "`systemctl start`" (and similar commands) and asks passwords to the user during manual startup of a service
|
||||||
* A simple tty agent which can be run manually to respond to all queued passwords
|
* A simple tty agent which can be run manually to respond to all queued passwords
|
||||||
|
|
||||||
|
## Implementing Agents
|
||||||
|
|
||||||
It is easy to write additional agents. The basic algorithm to follow looks like this:
|
It is easy to write additional agents. The basic algorithm to follow looks like this:
|
||||||
|
|
||||||
* Create an inotify watch on /run/systemd/ask-password, watch for `IN_CLOSE_WRITE|IN_MOVED_TO`
|
* Create an inotify watch on `/run/systemd/ask-password/`, watch for `IN_CLOSE_WRITE|IN_MOVED_TO`
|
||||||
* Ignore all events on files in that directory that do not start with "`ask.`"
|
* Ignore all events on files in that directory that do not start with "`ask.`"
|
||||||
* As soon as a file named "`ask.xxxx`" shows up, read it. It's a simple `.ini` file that may be parsed with the usual parsers. The `xxxx` suffix is randomized.
|
* As soon as a file named "`ask.xxxx`" shows up, read it. It's a simple `.ini` file that may be parsed with the usual parsers. The `xxxx` suffix is randomized.
|
||||||
* Make sure to ignore unknown `.ini` file keys in those files, so that we can easily extend the format later on.
|
* Make sure to ignore unknown `.ini` file keys in those files, so that we can easily extend the format later on.
|
||||||
|
@ -42,23 +47,57 @@ It is easy to write additional agents. The basic algorithm to follow looks like
|
||||||
* Make sure to hide a password query dialog as soon as a) the `ask.xxxx` file is deleted, watch this with inotify. b) the `NotAfter=` time elapses, if it is set `!= 0`.
|
* Make sure to hide a password query dialog as soon as a) the `ask.xxxx` file is deleted, watch this with inotify. b) the `NotAfter=` time elapses, if it is set `!= 0`.
|
||||||
* Access to the socket is restricted to privileged users.
|
* Access to the socket is restricted to privileged users.
|
||||||
To acquire the necessary privileges to send the answer back, consider using PolicyKit.
|
To acquire the necessary privileges to send the answer back, consider using PolicyKit.
|
||||||
In fact, the GNOME agent we ship does that, and you may simply piggyback on that, by executing "`/usr/bin/pkexec /lib/systemd/systemd-reply-password 1 /path/to/socket`" or "`/usr/bin/pkexec /lib/systemd/systemd-reply-password 0 /path/to/socket`" and writing the password to its standard input.
|
For convenience, an reference implementation is provided by executing "`/usr/bin/pkexec /lib/systemd/systemd-reply-password 1 /path/to/socket`" or "`/usr/bin/pkexec /lib/systemd/systemd-reply-password 0 /path/to/socket`" and writing the password to its standard input.
|
||||||
Use '`1`' as argument if a password was entered by the user, or '`0`' if the user canceled the request.
|
Use '`1`' as argument if a password was entered by the user, or '`0`' if the user canceled the request.
|
||||||
* If you do not want to use PK ensure to acquire the necessary privileges in some other way and send a single datagram
|
* If you do not want to use PK ensure to acquire the necessary privileges in some other way and send a single datagram
|
||||||
to the socket consisting of the password string either prefixed with "`+`" or with "`-`" depending on whether the password entry was successful or not.
|
to the socket consisting of the password string either prefixed with "`+`" or with "`-`" depending on whether the password entry was successful or not.
|
||||||
You may but don't have to include a final `NUL` byte in your message.
|
You may but don't have to include a final `NUL` byte in your message.
|
||||||
|
|
||||||
Again, it is essential that you stop showing the password box/notification/status icon if the `ask.xxx` file is removed or when `NotAfter=` elapses (if it is set `!= 0`)!
|
Again, it is essential that you stop showing the password
|
||||||
|
box/notification/status icon if the `ask.xxxx` file is removed or when
|
||||||
|
`NotAfter=` elapses (if it is set `!= 0`)!
|
||||||
|
|
||||||
It may happen that multiple password entries are pending at the same time.
|
It may happen that multiple password entries are pending at the same time.
|
||||||
Your agent needs to be able to deal with that. Depending on your environment you may either choose to show all outstanding passwords at the same time or instead only one and as soon as the user has replied to that one go on to the next one.
|
Your agent needs to be able to deal with that. Depending on your environment
|
||||||
|
you may either choose to show all outstanding passwords at the same time or
|
||||||
|
instead only one and as soon as the user has replied to that one go on to the
|
||||||
|
next one.
|
||||||
|
|
||||||
You may test this all with manually invoking the "`systemd-ask-password`" tool on the command line.
|
If you write a system level agent, a smart way to activate it is using systemd
|
||||||
Pass `--no-tty` to ensure the password is asked via the agent system.
|
`.path` units. This will ensure that systemd will watch the
|
||||||
Note that only privileged users may use this tool (after all this is intended purely for system-level passwords).
|
`/run/systemd/ask-password/` directory and spawn the agent as soon as that
|
||||||
|
directory becomes non-empty. In fact, the console, wall and Plymouth agents
|
||||||
|
are started like this. If systemd is used to maintain user sessions as well
|
||||||
|
you can use a similar scheme to automatically spawn your user password agent as
|
||||||
|
well.
|
||||||
|
|
||||||
If you write a system level agent a smart way to activate it is using systemd `.path` units.
|
## Implementing Queriers
|
||||||
This will ensure that systemd will watch the `/run/systemd/ask-password` directory and spawn the agent as soon as that directory becomes non-empty.
|
|
||||||
In fact, the console, wall and Plymouth agents are started like this.
|
It's also easy to implement applications that want to query passwords this way
|
||||||
If systemd is used to maintain user sessions as well you can use a similar scheme to automatically spawn your user password agent as well.
|
(i.e. client for the agents above). Simply bind an `AF_UNIX`/`SOCK_DGRAM`
|
||||||
(As of this moment we have not switched any DE over to use systemd for session management, however.)
|
socket somewhere (suggestion: you can do this in `/run/systemd/ask-password/`
|
||||||
|
under a randomized socket name, not beginning with `ask.`). Then, create an
|
||||||
|
`/run/systemd/ask-password/ask.xxxx` (replace the `xxxx` by some randomized
|
||||||
|
string) file, with the appropriate `Message=`, `PID=`, `Icon=`, `Echo=`,
|
||||||
|
`NotAfter=` fields in the `[Ask]` section. Most importantly, include `Socket=`
|
||||||
|
pointing to your socket entrypoint. Then, just wait until the password is
|
||||||
|
delivered to you on the socket. Finally, don't forget to remove the file and
|
||||||
|
the socket once done.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
You may test agents by manually invoking the "`systemd-ask-password`" tool from
|
||||||
|
a shell. Pass `--no-tty` to ensure the password is asked via the agent system.
|
||||||
|
|
||||||
|
You may test queriers by manually invoking the
|
||||||
|
"`systemd-tty-ask-password-agent`" from a shell.
|
||||||
|
|
||||||
|
## Unprivileged Per-User Password Agents
|
||||||
|
|
||||||
|
Starting with systemd v257 the scheme is extended to per-user password
|
||||||
|
agents. A second per-user directory `$XDG_RUNTIME_DIR/systemd/ask-password/` is
|
||||||
|
now available, with the same protocol as the system-wide
|
||||||
|
counterpart. Unprivileged, per-directory agents should watch this directory in
|
||||||
|
parallel to the system-wide one. Unprivileged queriers (i.e. clients to these
|
||||||
|
agents) should pick the per-user directory to place their password request
|
||||||
|
files in.
|
||||||
|
|
|
@ -760,8 +760,9 @@ sensor:modalias:i2c:bmc150_accel:dmi:*:svnLENOVO:*:pvrLenovoYoga300-11IBR:*
|
||||||
sensor:modalias:acpi:ACCL0001*:dmi:*:svnLENOVO:pn60072:pvr851*:*
|
sensor:modalias:acpi:ACCL0001*:dmi:*:svnLENOVO:pn60072:pvr851*:*
|
||||||
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
|
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
|
||||||
|
|
||||||
# IdeaPad Duet 3 10IGL5 (82AT)
|
# IdeaPad Duet 3 10IGL5 (82AT) and 10IGL5-LTE (82HK)
|
||||||
sensor:modalias:acpi:SMO8B30*:dmi:*:svnLENOVO*:pn82AT:*
|
sensor:modalias:acpi:SMO8B30*:dmi:*:svnLENOVO*:pn82AT:*
|
||||||
|
sensor:modalias:acpi:SMO8B30*:dmi:*:svnLENOVO*:pn82HK:*
|
||||||
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
|
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
|
|
|
@ -593,8 +593,6 @@ node /org/freedesktop/systemd1 {
|
||||||
|
|
||||||
<!--method GetJobBefore is not documented!-->
|
<!--method GetJobBefore is not documented!-->
|
||||||
|
|
||||||
<!--method SetShowStatus is not documented!-->
|
|
||||||
|
|
||||||
<!--method ListUnitsFiltered is not documented!-->
|
<!--method ListUnitsFiltered is not documented!-->
|
||||||
|
|
||||||
<!--method ListUnitsByPatterns is not documented!-->
|
<!--method ListUnitsByPatterns is not documented!-->
|
||||||
|
@ -673,8 +671,6 @@ node /org/freedesktop/systemd1 {
|
||||||
|
|
||||||
<!--property ConfirmSpawn is not documented!-->
|
<!--property ConfirmSpawn is not documented!-->
|
||||||
|
|
||||||
<!--property ShowStatus is not documented!-->
|
|
||||||
|
|
||||||
<!--property DefaultStandardOutput is not documented!-->
|
<!--property DefaultStandardOutput is not documented!-->
|
||||||
|
|
||||||
<!--property DefaultStandardError is not documented!-->
|
<!--property DefaultStandardError is not documented!-->
|
||||||
|
@ -1362,6 +1358,24 @@ node /org/freedesktop/systemd1 {
|
||||||
|
|
||||||
<para><function>ResetFailedUnit()</function> resets the "failed" state of a specific unit.</para>
|
<para><function>ResetFailedUnit()</function> resets the "failed" state of a specific unit.</para>
|
||||||
|
|
||||||
|
<para><function>SetShowStatus()</function> configures the display of status messages during bootup and
|
||||||
|
shutdown. The <varname>mode</varname> parameter can be set to any value that's valid for the
|
||||||
|
<varname>systemd.show_status</varname> kernel parameter. For more information about
|
||||||
|
<varname>systemd.show_status</varname>, see
|
||||||
|
<citerefentry project="man-pages"><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
|
||||||
|
The <varname>mode</varname> parameter can also be set to an empty string. When <varname>mode</varname>
|
||||||
|
is set to an empty string, <function>SetShowStatus()</function> will reset
|
||||||
|
<varname>ShowStatus</varname> back to its original value. You can use
|
||||||
|
<function>SetShowStatus()</function> create a service that does something like this:
|
||||||
|
<orderedlist>
|
||||||
|
<listitem><para>Send a D-Bus message that will turn off status messages.</para></listitem>
|
||||||
|
<listitem><para>Block until a reply to that message is received.</para></listitem>
|
||||||
|
<listitem><para>Print multiples lines without being interrupted by status messages.</para></listitem>
|
||||||
|
<listitem><para>Send a D-Bus message that will reset <varname>ShowStatus</varname> back to its
|
||||||
|
original value.</para></listitem>
|
||||||
|
</orderedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
<para><function>ResetFailed()</function> resets the "failed" state of all units.</para>
|
<para><function>ResetFailed()</function> resets the "failed" state of all units.</para>
|
||||||
|
|
||||||
<para><function>ListUnits()</function> returns an array of all currently loaded units. Note that
|
<para><function>ListUnits()</function> returns an array of all currently loaded units. Note that
|
||||||
|
@ -1788,6 +1802,12 @@ node /org/freedesktop/systemd1 {
|
||||||
<para><varname>Environment</varname> encodes the environment block passed to all executed services. It
|
<para><varname>Environment</varname> encodes the environment block passed to all executed services. It
|
||||||
may be altered with bus calls such as <function>SetEnvironment()</function> (see above).</para>
|
may be altered with bus calls such as <function>SetEnvironment()</function> (see above).</para>
|
||||||
|
|
||||||
|
<para><varname>ShowStatus</varname> encodes systemd's current policy for displaying status messages
|
||||||
|
during bootup and shutdown. Its value can be any valid value for the
|
||||||
|
<varname>systemd.show_status</varname> kernel parameter (see
|
||||||
|
<citerefentry project="man-pages"><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).
|
||||||
|
It may be altered using <function>SetShowStatus()</function> (see above).</para>
|
||||||
|
|
||||||
<para><varname>UnitPath</varname> encodes the currently active unit file search path. It is an array of
|
<para><varname>UnitPath</varname> encodes the currently active unit file search path. It is an array of
|
||||||
file system paths encoded as strings.</para>
|
file system paths encoded as strings.</para>
|
||||||
|
|
||||||
|
|
|
@ -483,18 +483,18 @@
|
||||||
<term><varname>ExcludeFiles=</varname></term>
|
<term><varname>ExcludeFiles=</varname></term>
|
||||||
<term><varname>ExcludeFilesTarget=</varname></term>
|
<term><varname>ExcludeFilesTarget=</varname></term>
|
||||||
|
|
||||||
<listitem><para>Takes an absolute file system path referring to a source file or directory on the
|
<listitem><para>Takes one or more absolute paths, separated by whitespace, each referring to a
|
||||||
host. This setting may be used to exclude files or directories from the host from being copied into
|
source file or directory on the host. This setting may be used to exclude files or directories from
|
||||||
the file system when <varname>CopyFiles=</varname> is used. This option may be used multiple times to
|
the host from being copied into the file system when <varname>CopyFiles=</varname> is used. This
|
||||||
exclude multiple files or directories from host from being copied into the newly formatted file
|
option may be used multiple times to exclude multiple files or directories from host from being
|
||||||
system.</para>
|
copied into the newly formatted file system.</para>
|
||||||
|
|
||||||
<para>If the path is a directory and ends with <literal>/</literal>, only the directory's
|
<para>If the path is a directory and ends with <literal>/</literal>, only the directory's
|
||||||
contents are excluded but not the directory itself. If the path is a directory and does not end with
|
contents are excluded but not the directory itself. If the path is a directory and does not end with
|
||||||
<literal>/</literal>, both the directory and its contents are excluded.</para>
|
<literal>/</literal>, both the directory and its contents are excluded.</para>
|
||||||
|
|
||||||
<para><varname>ExcludeFilesTarget=</varname> is like <varname>ExcludeFiles=</varname> except that
|
<para><varname>ExcludeFilesTarget=</varname> is like <varname>ExcludeFiles=</varname> except that
|
||||||
instead of excluding the path on the host from being copied into the partition, we exclude any files
|
instead of excluding the path on the host from being copied into the partition, it exclude any files
|
||||||
and directories from being copied into the given path in the partition.</para>
|
and directories from being copied into the given path in the partition.</para>
|
||||||
|
|
||||||
<para>When
|
<para>When
|
||||||
|
@ -922,9 +922,9 @@
|
||||||
target for some other supplement definition. A target cannot have more than one supplement partition
|
target for some other supplement definition. A target cannot have more than one supplement partition
|
||||||
associated with it.</para>
|
associated with it.</para>
|
||||||
|
|
||||||
<para>For example, distributions can use this to implement <variable>$BOOT</variable> as defined in
|
<para>For example, distributions can use this to implement <varname>$BOOT</varname> as defined in
|
||||||
the <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification/">Boot Loader
|
the <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification/">Boot Loader
|
||||||
Specification</ulink>. Distributions may prefer to use the ESP as <variable>$BOOT</variable> whenever
|
Specification</ulink>. Distributions may prefer to use the ESP as <varname>$BOOT</varname> whenever
|
||||||
possible, but to adhere to the spec XBOOTLDR must sometimes be used instead. So, they should create
|
possible, but to adhere to the spec XBOOTLDR must sometimes be used instead. So, they should create
|
||||||
two definitions: the first defining an ESP big enough to hold just the bootloader, and a second for
|
two definitions: the first defining an ESP big enough to hold just the bootloader, and a second for
|
||||||
the XBOOTLDR that's sufficiently large to hold kernels and configured as a supplement for the ESP.
|
the XBOOTLDR that's sufficiently large to hold kernels and configured as a supplement for the ESP.
|
||||||
|
|
|
@ -30,26 +30,22 @@
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Description</title>
|
<title>Description</title>
|
||||||
|
|
||||||
<para><command>systemd-ask-password</command> may be used to query
|
<para><command>systemd-ask-password</command> may be used to query a password or passphrase interactively
|
||||||
a system password or passphrase from the user, using a question
|
from the user, using a question prompt specified on the command line. When run from a TTY it will query a
|
||||||
message specified on the command line. When run from a TTY it will
|
password on the TTY and print it to standard output. When run with no TTY or with
|
||||||
query a password on the TTY and print it to standard output. When
|
<option>--no-tty</option> it will use a system-wide or per-user agent-based query mechanism, which allows
|
||||||
run with no TTY or with <option>--no-tty</option> it will use the
|
active users to respond via several agents, listed below.</para>
|
||||||
system-wide query mechanism, which allows active users to respond via
|
|
||||||
several agents, listed below.</para>
|
|
||||||
|
|
||||||
<para>The purpose of this tool is to query system-wide passwords
|
<para>The purpose of this tool is to query system-wide or per-user passwords — the former includes
|
||||||
— that is passwords not attached to a specific user account.
|
passwords possibly not associated to a specific user account. Examples include: unlocking encrypted hard
|
||||||
Examples include: unlocking encrypted hard disks when they are
|
disks when they are plugged in or at boot, entering an SSL certificate passphrase for web and VPN
|
||||||
plugged in or at boot, entering an SSL certificate passphrase for
|
servers.</para>
|
||||||
web and VPN servers.</para>
|
|
||||||
|
|
||||||
<para>Existing agents are:
|
<para>Existing system-level agents are:
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
|
|
||||||
<listitem><para>A boot-time password agent asking the user for
|
<listitem><para>A boot-time password agent asking the user for passwords using <citerefentry
|
||||||
passwords using
|
project='die-net'><refentrytitle>plymouth</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||||
<citerefentry project='die-net'><refentrytitle>plymouth</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
|
||||||
<listitem><para>A boot-time password agent querying the user
|
<listitem><para>A boot-time password agent querying the user
|
||||||
|
@ -77,17 +73,15 @@
|
||||||
all the agents listed above (except for the last one), run as privileged
|
all the agents listed above (except for the last one), run as privileged
|
||||||
system services. The last one also needs elevated privileges, so
|
system services. The last one also needs elevated privileges, so
|
||||||
should be run through
|
should be run through
|
||||||
<citerefentry project='die-net'><refentrytitle>sudo</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>run0</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||||
or similar.</para>
|
or similar.</para>
|
||||||
|
|
||||||
<para>Additional password agents may be implemented according to
|
<para>Additional password agents may be implemented according to the <ulink
|
||||||
the <ulink url="https://systemd.io/PASSWORD_AGENTS/">systemd Password Agent
|
url="https://systemd.io/PASSWORD_AGENTS/">systemd Password Agent Specification</ulink>.</para>
|
||||||
Specification</ulink>.</para>
|
|
||||||
|
|
||||||
<para>If a password is queried on a TTY, the user may press TAB to
|
<para>If a password is queried on a TTY, the user may press TAB to
|
||||||
hide the asterisks normally shown for each character typed.
|
hide the asterisks normally shown for each character typed.
|
||||||
Pressing Backspace as first key achieves the same effect.</para>
|
Pressing Backspace as first key achieves the same effect.</para>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
@ -241,6 +235,17 @@
|
||||||
<xi:include href="version-info.xml" xpointer="v249"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v249"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--user</option></term>
|
||||||
|
<term><option>--system</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Controls whether to query the system-wide or the per-user password agents. By default
|
||||||
|
if invoked privileged the system-wide agents are queried, otherwise the per-user ones. These options
|
||||||
|
allow to override this automatic behaviour.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<xi:include href="standard-options.xml" xpointer="help" />
|
<xi:include href="standard-options.xml" xpointer="help" />
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
|
|
@ -3001,7 +3001,12 @@ SystemCallErrorNumber=EPERM</programlisting>
|
||||||
|
|
||||||
<para><option>tty</option> connects standard output to a tty (as configured via <varname>TTYPath=</varname>,
|
<para><option>tty</option> connects standard output to a tty (as configured via <varname>TTYPath=</varname>,
|
||||||
see below). If the TTY is used for output only, the executed process will not become the controlling process of
|
see below). If the TTY is used for output only, the executed process will not become the controlling process of
|
||||||
the terminal, and will not fail or wait for other processes to release the terminal.</para>
|
the terminal, and will not fail or wait for other processes to release the terminal. Note: if a unit
|
||||||
|
tries to print multiple lines to a TTY during bootup or shutdown, then there's a chance that those
|
||||||
|
lines will be broken up by status messages. <function>SetShowStatus()</function> can be used to
|
||||||
|
prevent this problem. See
|
||||||
|
<citerefentry project="man-pages"><refentrytitle>org.freedesktop.systemd1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||||
|
for details.</para>
|
||||||
|
|
||||||
<para><option>journal</option> connects standard output with the journal, which is accessible via
|
<para><option>journal</option> connects standard output with the journal, which is accessible via
|
||||||
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. Note
|
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. Note
|
||||||
|
|
|
@ -568,7 +568,11 @@
|
||||||
<listitem><para>Enables display of status messages on the
|
<listitem><para>Enables display of status messages on the
|
||||||
console, as controlled via
|
console, as controlled via
|
||||||
<varname>systemd.show_status=1</varname> on the kernel command
|
<varname>systemd.show_status=1</varname> on the kernel command
|
||||||
line.</para></listitem>
|
line.</para>
|
||||||
|
<para>You may want to use <function>SetShowStatus()</function> instead of
|
||||||
|
<constant>SIGRTMIN+20</constant> in order to prevent race conditions. See
|
||||||
|
<citerefentry project="man-pages"><refentrytitle>org.freedesktop.systemd1</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||||
|
</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
@ -579,7 +583,11 @@
|
||||||
controlled via
|
controlled via
|
||||||
<varname>systemd.show_status=0</varname>
|
<varname>systemd.show_status=0</varname>
|
||||||
on the kernel command
|
on the kernel command
|
||||||
line.</para></listitem>
|
line.</para>
|
||||||
|
<para>You may want to use <function>SetShowStatus()</function> instead of
|
||||||
|
<constant>SIGRTMIN+21</constant> in order to prevent race conditions. See
|
||||||
|
<citerefentry project="man-pages"><refentrytitle>org.freedesktop.systemd1</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||||
|
</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|
|
@ -38,7 +38,7 @@ static int help(void) {
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
printf("%1$s [OPTIONS...] MESSAGE\n\n"
|
printf("%1$s [OPTIONS...] MESSAGE\n\n"
|
||||||
"%3$sQuery the user for a system passphrase, via the TTY or a UI agent.%4$s\n\n"
|
"%3$sQuery the user for a passphrase, via the TTY or a UI agent.%4$s\n\n"
|
||||||
" -h --help Show this help\n"
|
" -h --help Show this help\n"
|
||||||
" --icon=NAME Icon name\n"
|
" --icon=NAME Icon name\n"
|
||||||
" --id=ID Query identifier (e.g. \"cryptsetup:/dev/sda5\")\n"
|
" --id=ID Query identifier (e.g. \"cryptsetup:/dev/sda5\")\n"
|
||||||
|
@ -58,6 +58,8 @@ static int help(void) {
|
||||||
" --no-output Do not print password to standard output\n"
|
" --no-output Do not print password to standard output\n"
|
||||||
" -n Do not suffix password written to standard output with\n"
|
" -n Do not suffix password written to standard output with\n"
|
||||||
" newline\n"
|
" newline\n"
|
||||||
|
" --user Ask only our own user's agents\n"
|
||||||
|
" --system Ask agents of the system and of all users\n"
|
||||||
"\nSee the %2$s for details.\n",
|
"\nSee the %2$s for details.\n",
|
||||||
program_invocation_short_name,
|
program_invocation_short_name,
|
||||||
link,
|
link,
|
||||||
|
@ -81,6 +83,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
ARG_NO_OUTPUT,
|
ARG_NO_OUTPUT,
|
||||||
ARG_VERSION,
|
ARG_VERSION,
|
||||||
ARG_CREDENTIAL,
|
ARG_CREDENTIAL,
|
||||||
|
ARG_USER,
|
||||||
|
ARG_SYSTEM,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
|
@ -97,6 +101,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
{ "keyname", required_argument, NULL, ARG_KEYNAME },
|
{ "keyname", required_argument, NULL, ARG_KEYNAME },
|
||||||
{ "no-output", no_argument, NULL, ARG_NO_OUTPUT },
|
{ "no-output", no_argument, NULL, ARG_NO_OUTPUT },
|
||||||
{ "credential", required_argument, NULL, ARG_CREDENTIAL },
|
{ "credential", required_argument, NULL, ARG_CREDENTIAL },
|
||||||
|
{ "user", no_argument, NULL, ARG_USER },
|
||||||
|
{ "system", no_argument, NULL, ARG_SYSTEM },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -183,6 +189,14 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
arg_credential_name = optarg;
|
arg_credential_name = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_USER:
|
||||||
|
arg_flags |= ASK_PASSWORD_USER;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_SYSTEM:
|
||||||
|
arg_flags &= ~ASK_PASSWORD_USER;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
arg_newline = false;
|
arg_newline = false;
|
||||||
break;
|
break;
|
||||||
|
@ -228,6 +242,9 @@ static int run(int argc, char *argv[]) {
|
||||||
|
|
||||||
log_setup();
|
log_setup();
|
||||||
|
|
||||||
|
/* Unprivileged? Then imply ASK_PASSWORD_USER by default */
|
||||||
|
SET_FLAG(arg_flags, ASK_PASSWORD_USER, geteuid() != 0);
|
||||||
|
|
||||||
r = parse_argv(argc, argv);
|
r = parse_argv(argc, argv);
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -282,13 +282,18 @@ static int have_ask_password(void) {
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
return false;
|
return false;
|
||||||
else
|
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
FOREACH_DIRENT_ALL(de, dir, return -errno)
|
FOREACH_DIRENT_ALL(de, dir, return -errno) {
|
||||||
|
if (!IN_SET(de->d_type, DT_REG, DT_UNKNOWN))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (startswith(de->d_name, "ask."))
|
if (startswith(de->d_name, "ask."))
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,9 +305,8 @@ static int manager_dispatch_ask_password_fd(sd_event_source *source,
|
||||||
|
|
||||||
m->have_ask_password = have_ask_password();
|
m->have_ask_password = have_ask_password();
|
||||||
if (m->have_ask_password < 0)
|
if (m->have_ask_password < 0)
|
||||||
/* Log error but continue. Negative have_ask_password
|
/* Log error but continue. Negative have_ask_password is treated as unknown status. */
|
||||||
* is treated as unknown status. */
|
log_warning_errno(m->have_ask_password, "Failed to list /run/systemd/ask-password/, ignoring: %m");
|
||||||
log_error_errno(m->have_ask_password, "Failed to list /run/systemd/ask-password: %m");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -311,7 +315,6 @@ static void manager_close_ask_password(Manager *m) {
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
m->ask_password_event_source = sd_event_source_disable_unref(m->ask_password_event_source);
|
m->ask_password_event_source = sd_event_source_disable_unref(m->ask_password_event_source);
|
||||||
m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd);
|
|
||||||
m->have_ask_password = -EINVAL;
|
m->have_ask_password = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,37 +323,43 @@ static int manager_check_ask_password(Manager *m) {
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
|
/* We only care about passwords prompts when running in system mode (because that's the only time we
|
||||||
|
* manage a console) */
|
||||||
|
if (!MANAGER_IS_SYSTEM(m))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!m->ask_password_event_source) {
|
if (!m->ask_password_event_source) {
|
||||||
assert(m->ask_password_inotify_fd < 0);
|
_cleanup_close_ int inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
|
||||||
|
if (inotify_fd < 0)
|
||||||
(void) mkdir_p_label("/run/systemd/ask-password", 0755);
|
|
||||||
|
|
||||||
m->ask_password_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
|
|
||||||
if (m->ask_password_inotify_fd < 0)
|
|
||||||
return log_error_errno(errno, "Failed to create inotify object: %m");
|
return log_error_errno(errno, "Failed to create inotify object: %m");
|
||||||
|
|
||||||
r = inotify_add_watch_and_warn(m->ask_password_inotify_fd,
|
(void) mkdir_p_label("/run/systemd/ask-password", 0755);
|
||||||
"/run/systemd/ask-password",
|
r = inotify_add_watch_and_warn(inotify_fd, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_DELETE|IN_MOVED_TO|IN_ONLYDIR);
|
||||||
IN_CREATE|IN_DELETE|IN_MOVE);
|
if (r < 0)
|
||||||
if (r < 0) {
|
|
||||||
manager_close_ask_password(m);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
|
||||||
|
|
||||||
r = sd_event_add_io(m->event, &m->ask_password_event_source,
|
_cleanup_(sd_event_source_disable_unrefp) sd_event_source *event_source = NULL;
|
||||||
m->ask_password_inotify_fd, EPOLLIN,
|
r = sd_event_add_io(
|
||||||
manager_dispatch_ask_password_fd, m);
|
m->event,
|
||||||
if (r < 0) {
|
&event_source,
|
||||||
log_error_errno(r, "Failed to add event source for /run/systemd/ask-password: %m");
|
inotify_fd,
|
||||||
manager_close_ask_password(m);
|
EPOLLIN,
|
||||||
return r;
|
manager_dispatch_ask_password_fd,
|
||||||
}
|
m);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to add event source for /run/systemd/ask-password/: %m");
|
||||||
|
|
||||||
(void) sd_event_source_set_description(m->ask_password_event_source, "manager-ask-password");
|
r = sd_event_source_set_io_fd_own(event_source, true);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to pass ownership of /run/systemd/ask-password/ inotify fd to event source: %m");
|
||||||
|
TAKE_FD(inotify_fd);
|
||||||
|
|
||||||
|
(void) sd_event_source_set_description(event_source, "manager-ask-password");
|
||||||
|
|
||||||
|
m->ask_password_event_source = TAKE_PTR(event_source);
|
||||||
|
|
||||||
/* Queries might have been added meanwhile... */
|
/* Queries might have been added meanwhile... */
|
||||||
manager_dispatch_ask_password_fd(m->ask_password_event_source,
|
(void) manager_dispatch_ask_password_fd(m->ask_password_event_source, sd_event_source_get_io_fd(m->ask_password_event_source), EPOLLIN, m);
|
||||||
m->ask_password_inotify_fd, EPOLLIN, m);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return m->have_ask_password;
|
return m->have_ask_password;
|
||||||
|
@ -908,7 +917,6 @@ int manager_new(RuntimeScope runtime_scope, ManagerTestRunFlags test_run_flags,
|
||||||
.dev_autofs_fd = -EBADF,
|
.dev_autofs_fd = -EBADF,
|
||||||
.cgroup_inotify_fd = -EBADF,
|
.cgroup_inotify_fd = -EBADF,
|
||||||
.pin_cgroupfs_fd = -EBADF,
|
.pin_cgroupfs_fd = -EBADF,
|
||||||
.ask_password_inotify_fd = -EBADF,
|
|
||||||
.idle_pipe = { -EBADF, -EBADF, -EBADF, -EBADF},
|
.idle_pipe = { -EBADF, -EBADF, -EBADF, -EBADF},
|
||||||
|
|
||||||
/* start as id #1, so that we can leave #0 around as "null-like" value */
|
/* start as id #1, so that we can leave #0 around as "null-like" value */
|
||||||
|
|
|
@ -433,7 +433,6 @@ struct Manager {
|
||||||
|
|
||||||
/* Do we have any outstanding password prompts? */
|
/* Do we have any outstanding password prompts? */
|
||||||
int have_ask_password;
|
int have_ask_password;
|
||||||
int ask_password_inotify_fd;
|
|
||||||
sd_event_source *ask_password_event_source;
|
sd_event_source *ask_password_event_source;
|
||||||
|
|
||||||
/* Type=idle pipes */
|
/* Type=idle pipes */
|
||||||
|
|
|
@ -4169,7 +4169,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||||
* detect when the cgroup becomes empty. Note that the control process is always
|
* detect when the cgroup becomes empty. Note that the control process is always
|
||||||
* our child so it's pointless to watch all other processes. */
|
* our child so it's pointless to watch all other processes. */
|
||||||
if (!control_pid_good(s))
|
if (!control_pid_good(s))
|
||||||
if (!s->main_pid_known || s->main_pid_alien)
|
if (!s->main_pid_known || s->main_pid_alien || unit_cgroup_delegate(u))
|
||||||
(void) unit_enqueue_rewatch_pids(u);
|
(void) unit_enqueue_rewatch_pids(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -404,15 +404,16 @@ static int context_set_path_strv(Context *c, char* const* strv, const char *sour
|
||||||
|
|
||||||
static int context_set_plugins(Context *c, const char *s, const char *source) {
|
static int context_set_plugins(Context *c, const char *s, const char *source) {
|
||||||
_cleanup_strv_free_ char **v = NULL;
|
_cleanup_strv_free_ char **v = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(c);
|
assert(c);
|
||||||
|
|
||||||
if (c->plugins || !s)
|
if (c->plugins || !s)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
v = strv_split(s, NULL);
|
r = strv_split_full(&v, s, NULL, EXTRACT_UNQUOTE);
|
||||||
if (!v)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_error_errno(r, "Failed to parse plugin paths from %s: %m", source);
|
||||||
|
|
||||||
return context_set_path_strv(c, v, source, "plugins", &c->plugins);
|
return context_set_path_strv(c, v, source, "plugins", &c->plugins);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,13 @@ echo 'DTBDTBDTBDTB' >"$D/sources/subdir/whatever.dtb"
|
||||||
|
|
||||||
export KERNEL_INSTALL_CONF_ROOT="$D/sources"
|
export KERNEL_INSTALL_CONF_ROOT="$D/sources"
|
||||||
# We "install" multiple plugins, but control which ones will be active via install.conf.
|
# We "install" multiple plugins, but control which ones will be active via install.conf.
|
||||||
export KERNEL_INSTALL_PLUGINS="${ukify_install} ${loaderentry_install} ${uki_copy_install}"
|
KERNEL_INSTALL_PLUGINS="'${loaderentry_install}' '${uki_copy_install}'"
|
||||||
|
if [[ -n "$ukify_install" ]]; then
|
||||||
|
# shellcheck disable=SC2089
|
||||||
|
KERNEL_INSTALL_PLUGINS="'${ukify_install}' $KERNEL_INSTALL_PLUGINS"
|
||||||
|
fi
|
||||||
|
# shellcheck disable=SC2090
|
||||||
|
export KERNEL_INSTALL_PLUGINS
|
||||||
export BOOT_ROOT="$D/boot"
|
export BOOT_ROOT="$D/boot"
|
||||||
export BOOT_MNT="$D/boot"
|
export BOOT_MNT="$D/boot"
|
||||||
export MACHINE_ID='3e0484f3634a418b8e6a39e8828b03e3'
|
export MACHINE_ID='3e0484f3634a418b8e6a39e8828b03e3'
|
||||||
|
|
|
@ -1742,8 +1742,9 @@ static int config_parse_exclude_files(
|
||||||
const char *rvalue,
|
const char *rvalue,
|
||||||
void *data,
|
void *data,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
_cleanup_free_ char *resolved = NULL;
|
|
||||||
char ***exclude_files = ASSERT_PTR(data);
|
char ***exclude_files = ASSERT_PTR(data);
|
||||||
|
const char *p = ASSERT_PTR(rvalue);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue)) {
|
||||||
|
@ -1751,20 +1752,34 @@ static int config_parse_exclude_files(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = specifier_printf(rvalue, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved);
|
for (;;) {
|
||||||
if (r < 0) {
|
_cleanup_free_ char *word = NULL, *resolved = NULL;
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
||||||
"Failed to expand specifiers in ExcludeFiles= path, ignoring: %s", rvalue);
|
r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
|
||||||
return 0;
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (r == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = specifier_printf(word, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||||
|
"Failed to expand specifiers in %s path, ignoring: %s", lvalue, word);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE|PATH_KEEP_TRAILING_SLASH, unit, filename, line, lvalue);
|
||||||
|
if (r < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strv_consume(exclude_files, TAKE_PTR(resolved)) < 0)
|
||||||
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
||||||
r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE|PATH_KEEP_TRAILING_SLASH, unit, filename, line, lvalue);
|
|
||||||
if (r < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (strv_consume(exclude_files, TAKE_PTR(resolved)) < 0)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "glyph-util.h"
|
#include "glyph-util.h"
|
||||||
|
#include "inotify-util.h"
|
||||||
#include "io-util.h"
|
#include "io-util.h"
|
||||||
#include "iovec-util.h"
|
#include "iovec-util.h"
|
||||||
#include "keyring-util.h"
|
#include "keyring-util.h"
|
||||||
|
@ -36,6 +37,7 @@
|
||||||
#include "missing_syscall.h"
|
#include "missing_syscall.h"
|
||||||
#include "mkdir-label.h"
|
#include "mkdir-label.h"
|
||||||
#include "nulstr-util.h"
|
#include "nulstr-util.h"
|
||||||
|
#include "path-lookup.h"
|
||||||
#include "plymouth-util.h"
|
#include "plymouth-util.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "random-util.h"
|
#include "random-util.h"
|
||||||
|
@ -57,7 +59,7 @@ static int lookup_key(const char *keyname, key_serial_t *ret) {
|
||||||
assert(keyname);
|
assert(keyname);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
serial = request_key("user", keyname, NULL, 0);
|
serial = request_key("user", keyname, /* callout_info= */ NULL, /* dest_keyring= */ 0);
|
||||||
if (serial == -1)
|
if (serial == -1)
|
||||||
return negative_errno();
|
return negative_errno();
|
||||||
|
|
||||||
|
@ -85,6 +87,28 @@ static int retrieve_key(key_serial_t serial, char ***ret) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_ask_password_directory_for_flags(AskPasswordFlags flags, char **ret) {
|
||||||
|
if (FLAGS_SET(flags, ASK_PASSWORD_USER))
|
||||||
|
return acquire_user_ask_password_directory(ret);
|
||||||
|
|
||||||
|
return strdup_to(ret, "/run/systemd/ask-password/"); /* Returns 1, indicating there's a suitable directory */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int touch_ask_password_directory(AskPasswordFlags flags) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
_cleanup_free_ char *p = NULL;
|
||||||
|
r = get_ask_password_directory_for_flags(flags, &p);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = touch(p);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 1; /* did something */
|
||||||
|
}
|
||||||
|
|
||||||
static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
|
static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
|
||||||
_cleanup_strv_free_erase_ char **l = NULL;
|
_cleanup_strv_free_erase_ char **l = NULL;
|
||||||
_cleanup_(erase_and_freep) char *p = NULL;
|
_cleanup_(erase_and_freep) char *p = NULL;
|
||||||
|
@ -107,7 +131,7 @@ static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **pa
|
||||||
} else if (r != -ENOKEY)
|
} else if (r != -ENOKEY)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = strv_extend_strv(&l, passwords, true);
|
r = strv_extend_strv(&l, passwords, /* filter_duplicates= */ true);
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -129,7 +153,7 @@ static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **pa
|
||||||
log_debug_errno(errno, "Failed to adjust kernel keyring key timeout: %m");
|
log_debug_errno(errno, "Failed to adjust kernel keyring key timeout: %m");
|
||||||
|
|
||||||
/* Tell everyone to check the keyring */
|
/* Tell everyone to check the keyring */
|
||||||
(void) touch("/run/systemd/ask-password");
|
(void) touch_ask_password_directory(flags);
|
||||||
|
|
||||||
log_debug("Added key to kernel keyring as %" PRIi32 ".", serial);
|
log_debug("Added key to kernel keyring as %" PRIi32 ".", serial);
|
||||||
|
|
||||||
|
@ -220,16 +244,16 @@ int ask_password_plymouth(
|
||||||
const char *flag_file,
|
const char *flag_file,
|
||||||
char ***ret) {
|
char ***ret) {
|
||||||
|
|
||||||
_cleanup_close_ int fd = -EBADF, notify = -EBADF;
|
_cleanup_close_ int fd = -EBADF, inotify_fd = -EBADF;
|
||||||
_cleanup_free_ char *packet = NULL;
|
_cleanup_free_ char *packet = NULL;
|
||||||
ssize_t k;
|
ssize_t k;
|
||||||
int r, n;
|
int r, n;
|
||||||
struct pollfd pollfd[2] = {};
|
|
||||||
char buffer[LINE_MAX];
|
char buffer[LINE_MAX];
|
||||||
size_t p = 0;
|
size_t p = 0;
|
||||||
enum {
|
enum {
|
||||||
POLL_SOCKET,
|
POLL_SOCKET,
|
||||||
POLL_INOTIFY
|
POLL_INOTIFY,
|
||||||
|
_POLL_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
@ -240,11 +264,11 @@ int ask_password_plymouth(
|
||||||
const char *message = req && req->message ? req->message : "Password:";
|
const char *message = req && req->message ? req->message : "Password:";
|
||||||
|
|
||||||
if (flag_file) {
|
if (flag_file) {
|
||||||
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
|
inotify_fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
|
||||||
if (notify < 0)
|
if (inotify_fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (inotify_add_watch(notify, flag_file, IN_ATTRIB) < 0) /* for the link count */
|
if (inotify_add_watch(inotify_fd, flag_file, IN_ATTRIB) < 0) /* for the link count */
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,10 +290,11 @@ int ask_password_plymouth(
|
||||||
|
|
||||||
CLEANUP_ERASE(buffer);
|
CLEANUP_ERASE(buffer);
|
||||||
|
|
||||||
pollfd[POLL_SOCKET].fd = fd;
|
struct pollfd pollfd[_POLL_MAX] = {
|
||||||
pollfd[POLL_SOCKET].events = POLLIN;
|
[POLL_SOCKET] = { .fd = fd, .events = POLLIN },
|
||||||
pollfd[POLL_INOTIFY].fd = notify;
|
[POLL_INOTIFY] = { .fd = inotify_fd, .events = POLLIN },
|
||||||
pollfd[POLL_INOTIFY].events = POLLIN;
|
};
|
||||||
|
size_t n_pollfd = inotify_fd >= 0 ? _POLL_MAX : _POLL_MAX-1;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
usec_t timeout;
|
usec_t timeout;
|
||||||
|
@ -282,7 +307,7 @@ int ask_password_plymouth(
|
||||||
if (flag_file && access(flag_file, F_OK) < 0)
|
if (flag_file && access(flag_file, F_OK) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
r = ppoll_usec(pollfd, notify >= 0 ? 2 : 1, timeout);
|
r = ppoll_usec(pollfd, n_pollfd, timeout);
|
||||||
if (r == -EINTR)
|
if (r == -EINTR)
|
||||||
continue;
|
continue;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -290,8 +315,8 @@ int ask_password_plymouth(
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
return -ETIME;
|
return -ETIME;
|
||||||
|
|
||||||
if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
|
if (inotify_fd >= 0 && pollfd[POLL_INOTIFY].revents != 0)
|
||||||
(void) flush_fd(notify);
|
(void) flush_fd(inotify_fd);
|
||||||
|
|
||||||
if (pollfd[POLL_SOCKET].revents == 0)
|
if (pollfd[POLL_SOCKET].revents == 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -382,11 +407,10 @@ int ask_password_tty(
|
||||||
};
|
};
|
||||||
|
|
||||||
bool reset_tty = false, dirty = false, use_color = false, press_tab_visible = false;
|
bool reset_tty = false, dirty = false, use_color = false, press_tab_visible = false;
|
||||||
_cleanup_close_ int cttyfd = -EBADF, notify = -EBADF;
|
_cleanup_close_ int cttyfd = -EBADF, inotify_fd = -EBADF;
|
||||||
struct termios old_termios, new_termios;
|
struct termios old_termios, new_termios;
|
||||||
char passphrase[LINE_MAX + 1] = {}, *x;
|
char passphrase[LINE_MAX + 1] = {}, *x;
|
||||||
_cleanup_strv_free_erase_ char **l = NULL;
|
_cleanup_strv_free_erase_ char **l = NULL;
|
||||||
struct pollfd pollfd[_POLL_MAX];
|
|
||||||
size_t p = 0, codepoint = 0;
|
size_t p = 0, codepoint = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -405,23 +429,36 @@ int ask_password_tty(
|
||||||
message = strjoina(special_glyph(SPECIAL_GLYPH_LOCK_AND_KEY), " ", message);
|
message = strjoina(special_glyph(SPECIAL_GLYPH_LOCK_AND_KEY), " ", message);
|
||||||
|
|
||||||
if (flag_file || (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && keyring)) {
|
if (flag_file || (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && keyring)) {
|
||||||
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
|
inotify_fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
|
||||||
if (notify < 0)
|
if (inotify_fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
if (flag_file) {
|
if (flag_file) {
|
||||||
if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0)
|
if (inotify_add_watch(inotify_fd, flag_file, IN_ATTRIB /* for the link count */) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && req && keyring) {
|
if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && req && keyring) {
|
||||||
r = ask_password_keyring(req, flags, ret);
|
r = ask_password_keyring(req, flags, ret);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
return 0;
|
return 0;
|
||||||
else if (r != -ENOKEY)
|
if (r != -ENOKEY)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_ATTRIB /* for mtime */) < 0)
|
/* Let's watch the askpw directory for mtime changes, which we issue above whenever the
|
||||||
return -errno;
|
* keyring changes */
|
||||||
|
_cleanup_free_ char *watch_path = NULL;
|
||||||
|
r = get_ask_password_directory_for_flags(flags, &watch_path);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r > 0) {
|
||||||
|
_cleanup_close_ int watch_fd = open_mkdir(watch_path, O_CLOEXEC|O_RDONLY, 0755);
|
||||||
|
if (watch_fd < 0)
|
||||||
|
return watch_fd;
|
||||||
|
|
||||||
|
r = inotify_add_watch_fd(inotify_fd, watch_fd, IN_ONLYDIR|IN_ATTRIB /* for mtime */);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CLEANUP_ERASE(passphrase);
|
CLEANUP_ERASE(passphrase);
|
||||||
|
@ -466,14 +503,11 @@ int ask_password_tty(
|
||||||
reset_tty = true;
|
reset_tty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pollfd[POLL_TTY] = (struct pollfd) {
|
struct pollfd pollfd[_POLL_MAX] = {
|
||||||
.fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO,
|
{ .fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO, .events = POLLIN },
|
||||||
.events = POLLIN,
|
{ .fd = inotify_fd, .events = POLLIN },
|
||||||
};
|
|
||||||
pollfd[POLL_INOTIFY] = (struct pollfd) {
|
|
||||||
.fd = notify,
|
|
||||||
.events = POLLIN,
|
|
||||||
};
|
};
|
||||||
|
size_t n_pollfd = inotify_fd >= 0 ? _POLL_MAX : _POLL_MAX-1;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
_cleanup_(erase_char) char c;
|
_cleanup_(erase_char) char c;
|
||||||
|
@ -491,7 +525,7 @@ int ask_password_tty(
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = ppoll_usec(pollfd, notify >= 0 ? 2 : 1, timeout);
|
r = ppoll_usec(pollfd, n_pollfd, timeout);
|
||||||
if (r == -EINTR)
|
if (r == -EINTR)
|
||||||
continue;
|
continue;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -501,8 +535,8 @@ int ask_password_tty(
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyring) {
|
if (inotify_fd >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyring) {
|
||||||
(void) flush_fd(notify);
|
(void) flush_fd(inotify_fd);
|
||||||
|
|
||||||
r = ask_password_keyring(req, flags, ret);
|
r = ask_password_keyring(req, flags, ret);
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
|
@ -659,20 +693,21 @@ finish:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int create_socket(char **ret) {
|
static int create_socket(const char *askpwdir, char **ret) {
|
||||||
_cleanup_free_ char *path = NULL;
|
_cleanup_free_ char *path = NULL;
|
||||||
union sockaddr_union sa;
|
union sockaddr_union sa;
|
||||||
socklen_t sa_len;
|
socklen_t sa_len;
|
||||||
_cleanup_close_ int fd = -EBADF;
|
_cleanup_close_ int fd = -EBADF;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
assert(askpwdir);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (asprintf(&path, "/run/systemd/ask-password/sck.%" PRIx64, random_u64()) < 0)
|
if (asprintf(&path, "%s/sck.%" PRIx64, askpwdir, random_u64()) < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = sockaddr_un_set_path(&sa.un, path);
|
r = sockaddr_un_set_path(&sa.un, path);
|
||||||
|
@ -699,19 +734,17 @@ int ask_password_agent(
|
||||||
char ***ret) {
|
char ***ret) {
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FD_SOCKET,
|
POLL_SOCKET,
|
||||||
FD_SIGNAL,
|
POLL_SIGNAL,
|
||||||
FD_INOTIFY,
|
POLL_INOTIFY,
|
||||||
_FD_MAX
|
_POLL_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
_cleanup_close_ int socket_fd = -EBADF, signal_fd = -EBADF, notify = -EBADF, fd = -EBADF;
|
_cleanup_close_ int socket_fd = -EBADF, signal_fd = -EBADF, inotify_fd = -EBADF, dfd = -EBADF;
|
||||||
char temp[] = "/run/systemd/ask-password/tmp.XXXXXX";
|
_cleanup_(unlink_and_freep) char *socket_name = NULL;
|
||||||
char final[sizeof(temp)] = "";
|
_cleanup_free_ char *temp = NULL, *final = NULL;
|
||||||
_cleanup_free_ char *socket_name = NULL;
|
|
||||||
_cleanup_strv_free_erase_ char **l = NULL;
|
_cleanup_strv_free_erase_ char **l = NULL;
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
struct pollfd pollfd[_FD_MAX];
|
|
||||||
sigset_t mask, oldmask;
|
sigset_t mask, oldmask;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -727,7 +760,20 @@ int ask_password_agent(
|
||||||
assert_se(sigset_add_many(&mask, SIGINT, SIGTERM) >= 0);
|
assert_se(sigset_add_many(&mask, SIGINT, SIGTERM) >= 0);
|
||||||
assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
|
assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
|
||||||
|
|
||||||
(void) mkdir_p_label("/run/systemd/ask-password", 0755);
|
_cleanup_free_ char *askpwdir = NULL;
|
||||||
|
r = get_ask_password_directory_for_flags(flags, &askpwdir);
|
||||||
|
if (r < 0)
|
||||||
|
goto finish;
|
||||||
|
if (r == 0) {
|
||||||
|
r = -ENXIO;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
dfd = open_mkdir(askpwdir, O_RDONLY|O_CLOEXEC, 0755);
|
||||||
|
if (dfd < 0) {
|
||||||
|
r = log_debug_errno(dfd, "Failed to open directory '%s': %m", askpwdir);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && req && req->keyring) {
|
if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && req && req->keyring) {
|
||||||
r = ask_password_keyring(req, flags, ret);
|
r = ask_password_keyring(req, flags, ret);
|
||||||
|
@ -737,30 +783,25 @@ int ask_password_agent(
|
||||||
} else if (r != -ENOKEY)
|
} else if (r != -ENOKEY)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
notify = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
|
inotify_fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
|
||||||
if (notify < 0) {
|
if (inotify_fd < 0) {
|
||||||
r = -errno;
|
r = -errno;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = RET_NERRNO(inotify_add_watch(notify, "/run/systemd/ask-password", IN_ATTRIB /* for mtime */));
|
r = inotify_add_watch_fd(inotify_fd, dfd, IN_ONLYDIR|IN_ATTRIB /* for mtime */);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = mkostemp_safe(temp);
|
if (asprintf(&final, "ask.%" PRIu64, random_u64()) < 0) {
|
||||||
if (fd < 0) {
|
r = -ENOMEM;
|
||||||
r = fd;
|
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) fchmod(fd, 0644);
|
r = fopen_temporary_at(dfd, final, &f, &temp);
|
||||||
|
if (r < 0)
|
||||||
f = take_fdopen(&fd, "w");
|
|
||||||
if (!f) {
|
|
||||||
r = -errno;
|
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
|
||||||
|
|
||||||
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
|
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
|
||||||
if (signal_fd < 0) {
|
if (signal_fd < 0) {
|
||||||
|
@ -768,7 +809,7 @@ int ask_password_agent(
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_fd = create_socket(&socket_name);
|
socket_fd = create_socket(askpwdir, &socket_name);
|
||||||
if (socket_fd < 0) {
|
if (socket_fd < 0) {
|
||||||
r = socket_fd;
|
r = socket_fd;
|
||||||
goto finish;
|
goto finish;
|
||||||
|
@ -800,27 +841,28 @@ int ask_password_agent(
|
||||||
fprintf(f, "Id=%s\n", req->id);
|
fprintf(f, "Id=%s\n", req->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fchmod(fileno(f), 0644) < 0) {
|
||||||
|
r = -errno;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
r = fflush_and_check(f);
|
r = fflush_and_check(f);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
memcpy(final, temp, sizeof(temp));
|
if (renameat(dfd, temp, dfd, final) < 0) {
|
||||||
|
r = -errno;
|
||||||
final[sizeof(final)-11] = 'a';
|
|
||||||
final[sizeof(final)-10] = 's';
|
|
||||||
final[sizeof(final)-9] = 'k';
|
|
||||||
|
|
||||||
r = RET_NERRNO(rename(temp, final));
|
|
||||||
if (r < 0)
|
|
||||||
goto finish;
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
zero(pollfd);
|
temp = mfree(temp);
|
||||||
pollfd[FD_SOCKET].fd = socket_fd;
|
|
||||||
pollfd[FD_SOCKET].events = POLLIN;
|
struct pollfd pollfd[_POLL_MAX] = {
|
||||||
pollfd[FD_SIGNAL].fd = signal_fd;
|
[POLL_SOCKET] = { .fd = socket_fd, .events = POLLIN },
|
||||||
pollfd[FD_SIGNAL].events = POLLIN;
|
[POLL_SIGNAL] = { .fd = signal_fd, .events = POLLIN },
|
||||||
pollfd[FD_INOTIFY].fd = notify;
|
[POLL_INOTIFY] = { .fd = inotify_fd, .events = POLLIN },
|
||||||
pollfd[FD_INOTIFY].events = POLLIN;
|
};
|
||||||
|
size_t n_pollfd = inotify_fd >= 0 ? _POLL_MAX : _POLL_MAX - 1;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
|
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
|
||||||
|
@ -835,7 +877,7 @@ int ask_password_agent(
|
||||||
else
|
else
|
||||||
timeout = USEC_INFINITY;
|
timeout = USEC_INFINITY;
|
||||||
|
|
||||||
r = ppoll_usec(pollfd, notify >= 0 ? _FD_MAX : _FD_MAX - 1, timeout);
|
r = ppoll_usec(pollfd, n_pollfd, timeout);
|
||||||
if (r == -EINTR)
|
if (r == -EINTR)
|
||||||
continue;
|
continue;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -845,13 +887,13 @@ int ask_password_agent(
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pollfd[FD_SIGNAL].revents & POLLIN) {
|
if (pollfd[POLL_SIGNAL].revents & POLLIN) {
|
||||||
r = -EINTR;
|
r = -EINTR;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notify >= 0 && pollfd[FD_INOTIFY].revents != 0) {
|
if (inotify_fd >= 0 && pollfd[POLL_INOTIFY].revents != 0) {
|
||||||
(void) flush_fd(notify);
|
(void) flush_fd(inotify_fd);
|
||||||
|
|
||||||
if (req && req->keyring) {
|
if (req && req->keyring) {
|
||||||
r = ask_password_keyring(req, flags, ret);
|
r = ask_password_keyring(req, flags, ret);
|
||||||
|
@ -863,10 +905,10 @@ int ask_password_agent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pollfd[FD_SOCKET].revents == 0)
|
if (pollfd[POLL_SOCKET].revents == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (pollfd[FD_SOCKET].revents != POLLIN) {
|
if (pollfd[POLL_SOCKET].revents != POLLIN) {
|
||||||
r = -EIO;
|
r = -EIO;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
@ -911,8 +953,8 @@ int ask_password_agent(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ucred->uid != 0) {
|
if (ucred->uid != getuid() && ucred->uid != 0) {
|
||||||
log_debug("Got request from unprivileged user. Ignoring.");
|
log_debug("Got response from bad user. Ignoring.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -951,13 +993,13 @@ int ask_password_agent(
|
||||||
r = 0;
|
r = 0;
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
if (socket_name)
|
if (temp) {
|
||||||
(void) unlink(socket_name);
|
assert(dfd >= 0);
|
||||||
|
(void) unlinkat(dfd, temp, 0);
|
||||||
(void) unlink(temp);
|
} else if (final) {
|
||||||
|
assert(dfd >= 0);
|
||||||
if (final[0])
|
(void) unlinkat(dfd, final, 0);
|
||||||
(void) unlink(final);
|
}
|
||||||
|
|
||||||
assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
|
assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
|
||||||
return r;
|
return r;
|
||||||
|
@ -1021,3 +1063,18 @@ int ask_password_auto(
|
||||||
|
|
||||||
return -EUNATCH;
|
return -EUNATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int acquire_user_ask_password_directory(char **ret) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = xdg_user_runtime_dir(ret, "systemd/ask-password");
|
||||||
|
if (r == -ENXIO) {
|
||||||
|
if (ret)
|
||||||
|
*ret = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
|
@ -6,16 +6,17 @@
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
typedef enum AskPasswordFlags {
|
typedef enum AskPasswordFlags {
|
||||||
ASK_PASSWORD_ACCEPT_CACHED = 1 << 0, /* read from kernel keyring */
|
ASK_PASSWORD_ACCEPT_CACHED = 1 << 0, /* read from kernel keyring */
|
||||||
ASK_PASSWORD_PUSH_CACHE = 1 << 1, /* write to kernel keyring after getting password from elsewhere */
|
ASK_PASSWORD_PUSH_CACHE = 1 << 1, /* write to kernel keyring after getting password from elsewhere */
|
||||||
ASK_PASSWORD_ECHO = 1 << 2, /* show the password literally while reading, instead of "*" */
|
ASK_PASSWORD_ECHO = 1 << 2, /* show the password literally while reading, instead of "*" */
|
||||||
ASK_PASSWORD_SILENT = 1 << 3, /* do no show any password at all while reading */
|
ASK_PASSWORD_SILENT = 1 << 3, /* do no show any password at all while reading */
|
||||||
ASK_PASSWORD_NO_TTY = 1 << 4, /* never ask for password on tty */
|
ASK_PASSWORD_NO_TTY = 1 << 4, /* never ask for password on tty */
|
||||||
ASK_PASSWORD_NO_AGENT = 1 << 5, /* never ask for password via agent */
|
ASK_PASSWORD_NO_AGENT = 1 << 5, /* never ask for password via agent */
|
||||||
ASK_PASSWORD_CONSOLE_COLOR = 1 << 6, /* Use color if /dev/console points to a console that supports color */
|
ASK_PASSWORD_CONSOLE_COLOR = 1 << 6, /* Use color if /dev/console points to a console that supports color */
|
||||||
ASK_PASSWORD_NO_CREDENTIAL = 1 << 7, /* never use $CREDENTIALS_DIRECTORY data */
|
ASK_PASSWORD_NO_CREDENTIAL = 1 << 7, /* never use $CREDENTIALS_DIRECTORY data */
|
||||||
ASK_PASSWORD_HIDE_EMOJI = 1 << 8, /* hide the lock and key emoji */
|
ASK_PASSWORD_HIDE_EMOJI = 1 << 8, /* hide the lock and key emoji */
|
||||||
ASK_PASSWORD_HEADLESS = 1 << 9, /* headless mode: never query interactively */
|
ASK_PASSWORD_HEADLESS = 1 << 9, /* headless mode: never query interactively */
|
||||||
|
ASK_PASSWORD_USER = 1 << 10, /* query only our own agents, not any system password agents */
|
||||||
} AskPasswordFlags;
|
} AskPasswordFlags;
|
||||||
|
|
||||||
/* Encapsulates the mostly static fields of a password query */
|
/* Encapsulates the mostly static fields of a password query */
|
||||||
|
@ -31,3 +32,5 @@ int ask_password_tty(int tty_fd, const AskPasswordRequest *req, usec_t until, As
|
||||||
int ask_password_plymouth(const AskPasswordRequest *req, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret);
|
int ask_password_plymouth(const AskPasswordRequest *req, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret);
|
||||||
int ask_password_agent(const AskPasswordRequest *req, usec_t until, AskPasswordFlags flag, char ***ret);
|
int ask_password_agent(const AskPasswordRequest *req, usec_t until, AskPasswordFlags flag, char ***ret);
|
||||||
int ask_password_auto(const AskPasswordRequest *req, usec_t until, AskPasswordFlags flag, char ***ret);
|
int ask_password_auto(const AskPasswordRequest *req, usec_t until, AskPasswordFlags flag, char ***ret);
|
||||||
|
|
||||||
|
int acquire_user_ask_password_directory(char **ret);
|
||||||
|
|
|
@ -197,7 +197,7 @@ _unused_ static void test_compress_stream(const char *compression,
|
||||||
ASSERT_OK(compress(src, dst, -1, &uncompressed_size));
|
ASSERT_OK(compress(src, dst, -1, &uncompressed_size));
|
||||||
|
|
||||||
if (cat) {
|
if (cat) {
|
||||||
assert_se(asprintf(&cmd, "%s %s | diff %s -", cat, pattern, srcfile) > 0);
|
assert_se(asprintf(&cmd, "%s %s | diff '%s' -", cat, pattern, srcfile) > 0);
|
||||||
assert_se(system(cmd) == 0);
|
assert_se(system(cmd) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ _unused_ static void test_compress_stream(const char *compression,
|
||||||
r = decompress(dst, dst2, st.st_size);
|
r = decompress(dst, dst2, st.st_size);
|
||||||
assert_se(r == 0);
|
assert_se(r == 0);
|
||||||
|
|
||||||
assert_se(asprintf(&cmd2, "diff %s %s", srcfile, pattern2) > 0);
|
assert_se(asprintf(&cmd2, "diff '%s' %s", srcfile, pattern2) > 0);
|
||||||
assert_se(system(cmd2) == 0);
|
assert_se(system(cmd2) == 0);
|
||||||
|
|
||||||
log_debug("/* test faulty decompression */");
|
log_debug("/* test faulty decompression */");
|
||||||
|
|
|
@ -55,40 +55,35 @@ static bool arg_console = false;
|
||||||
static const char *arg_device = NULL;
|
static const char *arg_device = NULL;
|
||||||
|
|
||||||
static int send_passwords(const char *socket_name, char **passwords) {
|
static int send_passwords(const char *socket_name, char **passwords) {
|
||||||
_cleanup_(erase_and_freep) char *packet = NULL;
|
|
||||||
_cleanup_close_ int socket_fd = -EBADF;
|
|
||||||
union sockaddr_union sa;
|
|
||||||
socklen_t sa_len;
|
|
||||||
size_t packet_length = 1;
|
|
||||||
char *d;
|
|
||||||
ssize_t n;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(socket_name);
|
assert(socket_name);
|
||||||
|
|
||||||
|
union sockaddr_union sa;
|
||||||
r = sockaddr_un_set_path(&sa.un, socket_name);
|
r = sockaddr_un_set_path(&sa.un, socket_name);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
sa_len = r;
|
socklen_t sa_len = r;
|
||||||
|
|
||||||
|
size_t packet_length = 1;
|
||||||
STRV_FOREACH(p, passwords)
|
STRV_FOREACH(p, passwords)
|
||||||
packet_length += strlen(*p) + 1;
|
packet_length += strlen(*p) + 1;
|
||||||
|
|
||||||
packet = new(char, packet_length);
|
_cleanup_(erase_and_freep) char *packet = new(char, packet_length);
|
||||||
if (!packet)
|
if (!packet)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
packet[0] = '+';
|
packet[0] = '+';
|
||||||
|
|
||||||
d = packet + 1;
|
char *d = packet + 1;
|
||||||
STRV_FOREACH(p, passwords)
|
STRV_FOREACH(p, passwords)
|
||||||
d = stpcpy(d, *p) + 1;
|
d = stpcpy(d, *p) + 1;
|
||||||
|
|
||||||
socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
|
_cleanup_close_ int socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
|
||||||
if (socket_fd < 0)
|
if (socket_fd < 0)
|
||||||
return log_debug_errno(errno, "socket(): %m");
|
return log_debug_errno(errno, "socket(): %m");
|
||||||
|
|
||||||
n = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, sa_len);
|
ssize_t n = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, sa_len);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
return log_debug_errno(errno, "sendto(): %m");
|
return log_debug_errno(errno, "sendto(): %m");
|
||||||
|
|
||||||
|
@ -96,12 +91,9 @@ static int send_passwords(const char *socket_name, char **passwords) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool wall_tty_match(const char *path, bool is_local, void *userdata) {
|
static bool wall_tty_match(const char *path, bool is_local, void *userdata) {
|
||||||
_cleanup_free_ char *p = NULL;
|
|
||||||
_cleanup_close_ int fd = -EBADF;
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
assert(path_is_absolute(path));
|
assert(path_is_absolute(path));
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
if (lstat(path, &st) < 0) {
|
if (lstat(path, &st) < 0) {
|
||||||
log_debug_errno(errno, "Failed to stat %s: %m", path);
|
log_debug_errno(errno, "Failed to stat %s: %m", path);
|
||||||
return true;
|
return true;
|
||||||
|
@ -120,12 +112,13 @@ static bool wall_tty_match(const char *path, bool is_local, void *userdata) {
|
||||||
* advantage that the block will automatically go away if the
|
* advantage that the block will automatically go away if the
|
||||||
* process dies. */
|
* process dies. */
|
||||||
|
|
||||||
|
_cleanup_free_ char *p = NULL;
|
||||||
if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) {
|
if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) {
|
||||||
log_oom();
|
log_oom_debug();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
|
_cleanup_close_ int fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
log_debug_errno(errno, "Failed to open the wall pipe: %m");
|
log_debug_errno(errno, "Failed to open the wall pipe: %m");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -162,6 +155,7 @@ static int agent_ask_password_tty(
|
||||||
r = ask_password_tty(tty_fd, &req, until, flags, flag_file, ret);
|
r = ask_password_tty(tty_fd, &req, until, flags, flag_file, ret);
|
||||||
|
|
||||||
if (arg_console) {
|
if (arg_console) {
|
||||||
|
assert(tty_fd >= 0);
|
||||||
tty_fd = safe_close(tty_fd);
|
tty_fd = safe_close(tty_fd);
|
||||||
release_terminal();
|
release_terminal();
|
||||||
|
|
||||||
|
@ -172,7 +166,7 @@ static int agent_ask_password_tty(
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_one_password_file(const char *filename) {
|
static int process_one_password_file(const char *filename, FILE *f) {
|
||||||
_cleanup_free_ char *socket_name = NULL, *message = NULL;
|
_cleanup_free_ char *socket_name = NULL, *message = NULL;
|
||||||
bool accept_cached = false, echo = false, silent = false;
|
bool accept_cached = false, echo = false, silent = false;
|
||||||
uint64_t not_after = 0;
|
uint64_t not_after = 0;
|
||||||
|
@ -192,13 +186,17 @@ static int process_one_password_file(const char *filename) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
|
assert(f);
|
||||||
|
|
||||||
r = config_parse(NULL, filename, NULL,
|
r = config_parse(/* unit= */ NULL,
|
||||||
NULL,
|
filename,
|
||||||
config_item_table_lookup, items,
|
f,
|
||||||
|
/* sections= */ "Ask\0",
|
||||||
|
config_item_table_lookup,
|
||||||
|
items,
|
||||||
CONFIG_PARSE_RELAXED|CONFIG_PARSE_WARN,
|
CONFIG_PARSE_RELAXED|CONFIG_PARSE_WARN,
|
||||||
NULL,
|
/* userdata= */ NULL,
|
||||||
NULL);
|
/* ret_stat= */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -297,41 +295,44 @@ static int wall_tty_block(void) {
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_password_files(void) {
|
static int process_password_files(const char *path) {
|
||||||
_cleanup_closedir_ DIR *d = NULL;
|
_cleanup_closedir_ DIR *d = NULL;
|
||||||
int r = 0;
|
int ret = 0, r;
|
||||||
|
|
||||||
d = opendir("/run/systemd/ask-password");
|
assert(path);
|
||||||
|
|
||||||
|
d = opendir(path);
|
||||||
if (!d) {
|
if (!d) {
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return log_error_errno(errno, "Failed to open /run/systemd/ask-password: %m");
|
return log_error_errno(errno, "Failed to open '%s': %m", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read directory: %m")) {
|
FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read directory '%s': %m", path)) {
|
||||||
_cleanup_free_ char *p = NULL;
|
_cleanup_free_ char *p = NULL;
|
||||||
int q;
|
|
||||||
|
|
||||||
/* We only support /run on tmpfs, hence we can rely on
|
if (!IN_SET(de->d_type, DT_REG, DT_UNKNOWN))
|
||||||
* d_type to be reliable */
|
|
||||||
|
|
||||||
if (de->d_type != DT_REG)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!startswith(de->d_name, "ask."))
|
if (!startswith(de->d_name, "ask."))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
p = path_join("/run/systemd/ask-password", de->d_name);
|
p = path_join(path, de->d_name);
|
||||||
if (!p)
|
if (!p)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
q = process_one_password_file(p);
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
if (q < 0 && r == 0)
|
r = xfopenat(dirfd(d), de->d_name, "re", O_NOFOLLOW, &f);
|
||||||
r = q;
|
if (r < 0) {
|
||||||
|
log_warning_errno(r, "Failed to open '%s', ignoring: %m", p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RET_GATHER(ret, process_one_password_file(p, f));
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_and_watch_password_files(bool watch) {
|
static int process_and_watch_password_files(bool watch) {
|
||||||
|
@ -341,6 +342,7 @@ static int process_and_watch_password_files(bool watch) {
|
||||||
_FD_MAX
|
_FD_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_cleanup_free_ char *user_ask_password_directory = NULL;
|
||||||
_unused_ _cleanup_close_ int tty_block_fd = -EBADF;
|
_unused_ _cleanup_close_ int tty_block_fd = -EBADF;
|
||||||
_cleanup_close_ int notify = -EBADF, signal_fd = -EBADF;
|
_cleanup_close_ int notify = -EBADF, signal_fd = -EBADF;
|
||||||
struct pollfd pollfd[_FD_MAX];
|
struct pollfd pollfd[_FD_MAX];
|
||||||
|
@ -351,6 +353,12 @@ static int process_and_watch_password_files(bool watch) {
|
||||||
|
|
||||||
(void) mkdir_p_label("/run/systemd/ask-password", 0755);
|
(void) mkdir_p_label("/run/systemd/ask-password", 0755);
|
||||||
|
|
||||||
|
r = acquire_user_ask_password_directory(&user_ask_password_directory);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to determine per-user password directory: %m");
|
||||||
|
if (r > 0)
|
||||||
|
(void) mkdir_p_label(user_ask_password_directory, 0755);
|
||||||
|
|
||||||
assert_se(sigemptyset(&mask) >= 0);
|
assert_se(sigemptyset(&mask) >= 0);
|
||||||
assert_se(sigset_add_many(&mask, SIGTERM) >= 0);
|
assert_se(sigset_add_many(&mask, SIGTERM) >= 0);
|
||||||
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) >= 0);
|
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) >= 0);
|
||||||
|
@ -366,29 +374,34 @@ static int process_and_watch_password_files(bool watch) {
|
||||||
if (notify < 0)
|
if (notify < 0)
|
||||||
return log_error_errno(errno, "Failed to allocate directory watch: %m");
|
return log_error_errno(errno, "Failed to allocate directory watch: %m");
|
||||||
|
|
||||||
r = inotify_add_watch_and_warn(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO);
|
r = inotify_add_watch_and_warn(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO|IN_ONLYDIR);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (user_ask_password_directory) {
|
||||||
|
r = inotify_add_watch_and_warn(notify, user_ask_password_directory, IN_CLOSE_WRITE|IN_MOVED_TO|IN_ONLYDIR);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
pollfd[FD_INOTIFY] = (struct pollfd) { .fd = notify, .events = POLLIN };
|
pollfd[FD_INOTIFY] = (struct pollfd) { .fd = notify, .events = POLLIN };
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
usec_t timeout = USEC_INFINITY;
|
usec_t timeout = USEC_INFINITY;
|
||||||
|
|
||||||
r = process_password_files();
|
r = process_password_files("/run/systemd/ask-password");
|
||||||
if (r < 0) {
|
if (user_ask_password_directory)
|
||||||
if (r == -ECANCELED)
|
RET_GATHER(r, process_password_files(user_ask_password_directory));
|
||||||
/* Disable poll() timeout since at least one password has
|
if (r == -ECANCELED)
|
||||||
* been skipped and therefore one file remains and is
|
/* Disable poll() timeout since at least one password has been skipped and therefore
|
||||||
* unlikely to trigger any events. */
|
* one file remains and is unlikely to trigger any events. */
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
else
|
else if (r < 0)
|
||||||
/* FIXME: we should do something here since otherwise the service
|
/* FIXME: we should do something here since otherwise the service
|
||||||
* requesting the password won't notice the error and will wait
|
* requesting the password won't notice the error and will wait
|
||||||
* indefinitely. */
|
* indefinitely. */
|
||||||
log_error_errno(r, "Failed to process password: %m");
|
log_warning_errno(r, "Failed to process password, ignoring: %m");
|
||||||
}
|
|
||||||
|
|
||||||
if (!watch)
|
if (!watch)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -52,7 +52,8 @@ static void test_event_spawn_self(const char *self, const char *arg, bool with_p
|
||||||
|
|
||||||
log_debug("/* %s(%s, %s) */", __func__, arg, yes_no(with_pidfd));
|
log_debug("/* %s(%s, %s) */", __func__, arg, yes_no(with_pidfd));
|
||||||
|
|
||||||
assert_se(cmd = strjoin(self, " ", arg));
|
/* 'self' may contain spaces, hence needs to be quoted. */
|
||||||
|
assert_se(cmd = strjoin("'", self, "' ", arg));
|
||||||
|
|
||||||
test_event_spawn_core(with_pidfd, cmd, result_buf, BUF_SIZE);
|
test_event_spawn_core(with_pidfd, cmd, result_buf, BUF_SIZE);
|
||||||
|
|
||||||
|
|
|
@ -4,32 +4,32 @@ set -e
|
||||||
|
|
||||||
ANALYZE="${1:-systemd-analyze}"
|
ANALYZE="${1:-systemd-analyze}"
|
||||||
|
|
||||||
$ANALYZE compare-versions 1 lt 2
|
"$ANALYZE" compare-versions 1 lt 2
|
||||||
$ANALYZE compare-versions 1 '<' 2
|
"$ANALYZE" compare-versions 1 '<' 2
|
||||||
$ANALYZE compare-versions 1 le 2
|
"$ANALYZE" compare-versions 1 le 2
|
||||||
$ANALYZE compare-versions 1 '<=' 2
|
"$ANALYZE" compare-versions 1 '<=' 2
|
||||||
$ANALYZE compare-versions 1 ne 2
|
"$ANALYZE" compare-versions 1 ne 2
|
||||||
$ANALYZE compare-versions 1 '!=' 2
|
"$ANALYZE" compare-versions 1 '!=' 2
|
||||||
( ! $ANALYZE compare-versions 1 ge 2 )
|
( ! "$ANALYZE" compare-versions 1 ge 2 )
|
||||||
( ! $ANALYZE compare-versions 1 '>=' 2 )
|
( ! "$ANALYZE" compare-versions 1 '>=' 2 )
|
||||||
( ! $ANALYZE compare-versions 1 eq 2 )
|
( ! "$ANALYZE" compare-versions 1 eq 2 )
|
||||||
( ! $ANALYZE compare-versions 1 '==' 2 )
|
( ! "$ANALYZE" compare-versions 1 '==' 2 )
|
||||||
( ! $ANALYZE compare-versions 1 gt 2 )
|
( ! "$ANALYZE" compare-versions 1 gt 2 )
|
||||||
( ! $ANALYZE compare-versions 1 '>' 2 )
|
( ! "$ANALYZE" compare-versions 1 '>' 2 )
|
||||||
|
|
||||||
test "$($ANALYZE compare-versions 1 2)" = '1 < 2'
|
test "$("$ANALYZE" compare-versions 1 2)" = '1 < 2'
|
||||||
test "$($ANALYZE compare-versions 2 2)" = '2 == 2'
|
test "$("$ANALYZE" compare-versions 2 2)" = '2 == 2'
|
||||||
test "$($ANALYZE compare-versions 2 1)" = '2 > 1'
|
test "$("$ANALYZE" compare-versions 2 1)" = '2 > 1'
|
||||||
test "$($ANALYZE compare-versions '' '')" = "'' == ''"
|
test "$("$ANALYZE" compare-versions '' '')" = "'' == ''"
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
|
|
||||||
$ANALYZE compare-versions 1 2; ret1=$?
|
"$ANALYZE" compare-versions 1 2; ret1=$?
|
||||||
$ANALYZE compare-versions 2 2; ret2=$?
|
"$ANALYZE" compare-versions 2 2; ret2=$?
|
||||||
$ANALYZE compare-versions 2 1; ret3=$?
|
"$ANALYZE" compare-versions 2 1; ret3=$?
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
test $ret1 == 12
|
test "$ret1" == 12
|
||||||
test $ret2 == 0
|
test "$ret2" == 0
|
||||||
test $ret3 == 11
|
test "$ret3" == 11
|
||||||
|
|
|
@ -44,9 +44,9 @@ test_one() (
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${input##*/}" =~ \.fstab\.input ]]; then
|
if [[ "${input##*/}" =~ \.fstab\.input ]]; then
|
||||||
SYSTEMD_LOG_LEVEL=debug SYSTEMD_IN_INITRD="$initrd" SYSTEMD_SYSFS_CHECK=no SYSTEMD_PROC_CMDLINE="fstab=yes root=fstab" SYSTEMD_FSTAB="$input" SYSTEMD_SYSROOT_FSTAB="/dev/null" $generator "$out" "$out" "$out"
|
SYSTEMD_LOG_LEVEL=debug SYSTEMD_IN_INITRD="$initrd" SYSTEMD_SYSFS_CHECK=no SYSTEMD_PROC_CMDLINE="fstab=yes root=fstab" SYSTEMD_FSTAB="$input" SYSTEMD_SYSROOT_FSTAB="/dev/null" "$generator" "$out" "$out" "$out"
|
||||||
else
|
else
|
||||||
SYSTEMD_LOG_LEVEL=debug SYSTEMD_IN_INITRD="$initrd" SYSTEMD_SYSFS_CHECK=no SYSTEMD_PROC_CMDLINE="fstab=no $(cat "$input")" $generator "$out" "$out" "$out"
|
SYSTEMD_LOG_LEVEL=debug SYSTEMD_IN_INITRD="$initrd" SYSTEMD_SYSFS_CHECK=no SYSTEMD_PROC_CMDLINE="fstab=no $(cat "$input")" "$generator" "$out" "$out" "$out"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# The option x-systemd.growfs creates symlink to system's systemd-growfs@.service in .mount.wants directory.
|
# The option x-systemd.growfs creates symlink to system's systemd-growfs@.service in .mount.wants directory.
|
||||||
|
|
|
@ -53,7 +53,7 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
|
||||||
echo "*** Running $f"
|
echo "*** Running $f"
|
||||||
prepare_testdir "${f%.input}"
|
prepare_testdir "${f%.input}"
|
||||||
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
||||||
$SYSUSERS --root="$TESTDIR"
|
"$SYSUSERS" --root="$TESTDIR"
|
||||||
|
|
||||||
compare "${f%.*}" ""
|
compare "${f%.*}" ""
|
||||||
done
|
done
|
||||||
|
@ -62,7 +62,7 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
|
||||||
echo "*** Running $f on stdin"
|
echo "*** Running $f on stdin"
|
||||||
prepare_testdir "${f%.input}"
|
prepare_testdir "${f%.input}"
|
||||||
touch "$TESTDIR/etc/sysusers.d/test.conf"
|
touch "$TESTDIR/etc/sysusers.d/test.conf"
|
||||||
$SYSUSERS --root="$TESTDIR" - <"$f"
|
"$SYSUSERS" --root="$TESTDIR" - <"$f"
|
||||||
|
|
||||||
compare "${f%.*}" "on stdin"
|
compare "${f%.*}" "on stdin"
|
||||||
done
|
done
|
||||||
|
@ -72,9 +72,9 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
|
||||||
prepare_testdir "${f%.input}"
|
prepare_testdir "${f%.input}"
|
||||||
touch "$TESTDIR/etc/sysusers.d/test.conf"
|
touch "$TESTDIR/etc/sysusers.d/test.conf"
|
||||||
# this overrides test.conf which is masked on disk
|
# this overrides test.conf which is masked on disk
|
||||||
$SYSUSERS --root="$TESTDIR" --replace=/etc/sysusers.d/test.conf - <"$f"
|
"$SYSUSERS" --root="$TESTDIR" --replace=/etc/sysusers.d/test.conf - <"$f"
|
||||||
# this should be ignored
|
# this should be ignored
|
||||||
$SYSUSERS --root="$TESTDIR" --replace=/usr/lib/sysusers.d/test.conf - <"$SOURCE/test-1.input"
|
"$SYSUSERS" --root="$TESTDIR" --replace=/usr/lib/sysusers.d/test.conf - <"$SOURCE/test-1.input"
|
||||||
|
|
||||||
compare "${f%.*}" "on stdin with --replace"
|
compare "${f%.*}" "on stdin with --replace"
|
||||||
done
|
done
|
||||||
|
@ -84,9 +84,9 @@ echo "*** Testing --inline"
|
||||||
prepare_testdir "$SOURCE/inline"
|
prepare_testdir "$SOURCE/inline"
|
||||||
# copy a random file to make sure it is ignored
|
# copy a random file to make sure it is ignored
|
||||||
cp "$f" "$TESTDIR/etc/sysusers.d/confuse.conf"
|
cp "$f" "$TESTDIR/etc/sysusers.d/confuse.conf"
|
||||||
$SYSUSERS --root="$TESTDIR" --inline \
|
"$SYSUSERS" --root="$TESTDIR" --inline \
|
||||||
"u u1 222 - - /bin/zsh" \
|
"u u1 222 - - /bin/zsh" \
|
||||||
"g g1 111"
|
"g g1 111"
|
||||||
|
|
||||||
compare "$SOURCE/inline" "(--inline)"
|
compare "$SOURCE/inline" "(--inline)"
|
||||||
|
|
||||||
|
@ -95,19 +95,19 @@ echo "*** Testing --inline with --replace"
|
||||||
prepare_testdir "$SOURCE/inline"
|
prepare_testdir "$SOURCE/inline"
|
||||||
# copy a random file to make sure it is ignored
|
# copy a random file to make sure it is ignored
|
||||||
cp "$f" "$TESTDIR/etc/sysusers.d/confuse.conf"
|
cp "$f" "$TESTDIR/etc/sysusers.d/confuse.conf"
|
||||||
$SYSUSERS --root="$TESTDIR" \
|
"$SYSUSERS" --root="$TESTDIR" \
|
||||||
--inline \
|
--inline \
|
||||||
--replace=/etc/sysusers.d/confuse.conf \
|
--replace=/etc/sysusers.d/confuse.conf \
|
||||||
"u u1 222 - - /bin/zsh" \
|
"u u1 222 - - /bin/zsh" \
|
||||||
"g g1 111"
|
"g g1 111"
|
||||||
|
|
||||||
compare "$SOURCE/inline" "(--inline --replace=…)"
|
compare "$SOURCE/inline" "(--inline --replace=…)"
|
||||||
|
|
||||||
echo "*** Testing --inline with no /etc"
|
echo "*** Testing --inline with no /etc"
|
||||||
rm -rf "${TESTDIR:?}/etc"
|
rm -rf "${TESTDIR:?}/etc"
|
||||||
$SYSUSERS --root="$TESTDIR" --inline \
|
"$SYSUSERS" --root="$TESTDIR" --inline \
|
||||||
"u u1 222 - - /bin/zsh" \
|
"u u1 222 - - /bin/zsh" \
|
||||||
"g g1 111"
|
"g g1 111"
|
||||||
|
|
||||||
compare "$SOURCE/inline" "(--inline)"
|
compare "$SOURCE/inline" "(--inline)"
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
|
||||||
echo "*** Running $f (with login.defs)"
|
echo "*** Running $f (with login.defs)"
|
||||||
prepare_testdir "${f%.input}"
|
prepare_testdir "${f%.input}"
|
||||||
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
||||||
$SYSUSERS --root="$TESTDIR"
|
"$SYSUSERS" --root="$TESTDIR"
|
||||||
|
|
||||||
# shellcheck disable=SC2050
|
# shellcheck disable=SC2050
|
||||||
[ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
|
[ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
|
||||||
|
@ -152,7 +152,7 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
|
||||||
echo "*** Running $f (with login.defs symlinked)"
|
echo "*** Running $f (with login.defs symlinked)"
|
||||||
prepare_testdir "${f%.input}"
|
prepare_testdir "${f%.input}"
|
||||||
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
||||||
$SYSUSERS --root="$TESTDIR"
|
"$SYSUSERS" --root="$TESTDIR"
|
||||||
|
|
||||||
# shellcheck disable=SC2050
|
# shellcheck disable=SC2050
|
||||||
[ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
|
[ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
|
||||||
|
@ -166,7 +166,7 @@ for f in $(find "$SOURCE"/unhappy-*.input | sort -V); do
|
||||||
echo "*** Running test $f"
|
echo "*** Running test $f"
|
||||||
prepare_testdir "${f%.input}"
|
prepare_testdir "${f%.input}"
|
||||||
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
||||||
SYSTEMD_LOG_LEVEL=info $SYSUSERS --root="$TESTDIR" 2>&1 | tail -n1 | sed -r 's/^[^:]+:[^:]+://' >"$TESTDIR/err"
|
SYSTEMD_LOG_LEVEL=info "$SYSUSERS" --root="$TESTDIR" 2>&1 | tail -n1 | sed -r 's/^[^:]+:[^:]+://' >"$TESTDIR/err"
|
||||||
if ! diff -u "$TESTDIR/err" "${f%.*}.expected-err"; then
|
if ! diff -u "$TESTDIR/err" "${f%.*}.expected-err"; then
|
||||||
echo >&2 "**** Unexpected error output for $f"
|
echo >&2 "**** Unexpected error output for $f"
|
||||||
cat >&2 "$TESTDIR/err"
|
cat >&2 "$TESTDIR/err"
|
||||||
|
|
Loading…
Reference in New Issue