Compare commits
27 Commits
6b89652cc5
...
6bee6c7ac6
Author | SHA1 | Date |
---|---|---|
Lennart Poettering | 6bee6c7ac6 | |
Yu Watanabe | 9671efff78 | |
Yu Watanabe | 4f0bc2582e | |
Yu Watanabe | 3292120adf | |
Yu Watanabe | f6cc5e1c8d | |
Yu Watanabe | 590f430cac | |
Mike Yuan | 93d2d36638 | |
Lennart Poettering | 369b12375b | |
Yu Watanabe | b5ec8f77e0 | |
Lennart Poettering | 3e0a3a0259 | |
Celeste Liu | 6573f0c82c | |
Daan De Meyer | e0258ac886 | |
Lennart Poettering | a859d0d378 | |
Lennart Poettering | db15657dfb | |
Lennart Poettering | 2aa3005ad2 | |
Lennart Poettering | 90cf998875 | |
Lennart Poettering | c8d60ae79d | |
Lennart Poettering | bfcf48b842 | |
Lennart Poettering | c6f007a468 | |
Lennart Poettering | 7fdaedf5af | |
Lennart Poettering | 9bbb7fcfcc | |
Lennart Poettering | fd0e60e2b1 | |
Lennart Poettering | 6226ebeb2b | |
Lennart Poettering | 5c095620e2 | |
Lennart Poettering | 1714b4f269 | |
Yu Watanabe | 5f5c5c48b9 | |
Yu Watanabe | 68fdef46a7 |
13
NEWS
13
NEWS
|
@ -2,6 +2,15 @@ systemd System and Service Manager
|
||||||
|
|
||||||
CHANGES WITH 257 in spe:
|
CHANGES WITH 257 in spe:
|
||||||
|
|
||||||
|
Incompatible changes:
|
||||||
|
|
||||||
|
* The --purge switch of systemd-tmpfiles (which was added in v256) has
|
||||||
|
been reworked: it will now only apply to tmpfiles.d/ lines marked
|
||||||
|
with the new "$" flag. This is an incompatible change, and means any
|
||||||
|
tmpfiles.d/ files which shall be used together with --purge need to
|
||||||
|
be updated accordingly. This change has been made to make it harder
|
||||||
|
to accidentally delete too many files when using --purge incorrectly.
|
||||||
|
|
||||||
Announcements of Future Feature Removals and Incompatible Changes:
|
Announcements of Future Feature Removals and Incompatible Changes:
|
||||||
|
|
||||||
* Support for automatic flushing of the nscd user/group database caches
|
* Support for automatic flushing of the nscd user/group database caches
|
||||||
|
@ -85,7 +94,7 @@ CHANGES WITH 257 in spe:
|
||||||
/usr/lib/clock-epoch, and /var/lib/systemd/timesync/clock. See
|
/usr/lib/clock-epoch, and /var/lib/systemd/timesync/clock. See
|
||||||
systemd(1) for an detailed updated description.
|
systemd(1) for an detailed updated description.
|
||||||
|
|
||||||
* Ctrl-Alt-Delete is reenabled during late shutdown, so that the user
|
* Ctrl-Alt-Delete is re-enabled during late shutdown, so that the user
|
||||||
can still initiate a reboot if the system freezes.
|
can still initiate a reboot if the system freezes.
|
||||||
|
|
||||||
* Unit option PrivateUsers=identity can be used to request a user
|
* Unit option PrivateUsers=identity can be used to request a user
|
||||||
|
@ -202,7 +211,7 @@ CHANGES WITH 257 in spe:
|
||||||
versions.
|
versions.
|
||||||
|
|
||||||
* systemd-sysupdate gained a new --transfer-source= option to set the
|
* systemd-sysupdate gained a new --transfer-source= option to set the
|
||||||
directory to which transfer sources cofigured with
|
directory to which transfer sources configured with
|
||||||
PathRelativeTo=explicit will be interpreted.
|
PathRelativeTo=explicit will be interpreted.
|
||||||
|
|
||||||
Miscellaneous:
|
Miscellaneous:
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -310,6 +310,10 @@ mouse:bluetooth:v047dp8019:name:Expert Wireless TB Mouse:*
|
||||||
ID_INPUT_TRACKBALL=1
|
ID_INPUT_TRACKBALL=1
|
||||||
MOUSE_DPI=400@125
|
MOUSE_DPI=400@125
|
||||||
|
|
||||||
|
# Kensington SlimBlade Pro trackball (via Bluetooth)
|
||||||
|
mouse:bluetooth:v047dp80d4:name:SlimBlade Pro:*
|
||||||
|
ID_INPUT_TRACKBALL=1
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# Lenovo
|
# Lenovo
|
||||||
##########################################
|
##########################################
|
||||||
|
|
|
@ -267,7 +267,8 @@
|
||||||
<term><option>kernel-identify</option> <replaceable>kernel</replaceable></term>
|
<term><option>kernel-identify</option> <replaceable>kernel</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Takes a kernel image as argument. Checks what kind of kernel the image is. Returns
|
<listitem><para>Takes a kernel image as argument. Checks what kind of kernel the image is. Returns
|
||||||
one of <literal>uki</literal>, <literal>pe</literal>, and <literal>unknown</literal>.
|
one of <literal>uki</literal>, <literal>addon</literal>, <literal>pe</literal>, and
|
||||||
|
<literal>unknown</literal>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
|
||||||
|
@ -360,6 +361,24 @@
|
||||||
<xi:include href="version-info.xml" xpointer="v242"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v242"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--print-loader-path</option></term>
|
||||||
|
<listitem><para>This option modifies the behaviour of <command>status</command>: it shows the
|
||||||
|
absolute path to the boot loader EFI binary used for the current boot if this information is
|
||||||
|
available. Note that no attempt is made to verify whether the binary still exists.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--print-stub-path</option></term>
|
||||||
|
<listitem><para>This option modifies the behaviour of <command>status</command>: it shows the
|
||||||
|
absolute path to the UKI/stub EFI binary used for the current boot if this information is
|
||||||
|
available. Note that no attempt is made to verify whether the binary still exists.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-R</option></term>
|
<term><option>-R</option></term>
|
||||||
<term><option>--print-root-device</option></term>
|
<term><option>--print-root-device</option></term>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@
|
||||||
result can be pre-calculated without too much effort. The <literal>.pcrsig</literal> section is not
|
result can be pre-calculated without too much effort. The <literal>.pcrsig</literal> section is not
|
||||||
included in this PCR measurement, since it is supposed to contain signatures for the output of the
|
included in this PCR measurement, since it is supposed to contain signatures for the output of the
|
||||||
measurement operation, and thus cannot also be input to it. If an UKI contains multiple profiles, only
|
measurement operation, and thus cannot also be input to it. If an UKI contains multiple profiles, only
|
||||||
the PE sections of the selected profile (and those of the base profile, except if overriden) are
|
the PE sections of the selected profile (and those of the base profile, except if overridden) are
|
||||||
measured.</para>
|
measured.</para>
|
||||||
|
|
||||||
<para>If non-zero, the selected numeric profile is measured into PCR 12.</para>
|
<para>If non-zero, the selected numeric profile is measured into PCR 12.</para>
|
||||||
|
|
|
@ -152,10 +152,11 @@
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--purge</option></term>
|
<term><option>--purge</option></term>
|
||||||
|
|
||||||
<listitem><para>If this option is passed, all files and directories marked for
|
<listitem><para>If this option is passed, all files and directories declared for
|
||||||
<emphasis>creation</emphasis> by the <filename>tmpfiles.d/</filename> files specified on the command
|
<emphasis>creation</emphasis> and marked with the <literal>$</literal> character by the
|
||||||
line will be <emphasis>deleted</emphasis>. Specifically, this acts on all files and directories
|
<filename>tmpfiles.d/</filename> files specified on the command line will be
|
||||||
marked with <varname>f</varname>, <varname>F</varname>, <varname>d</varname>, <varname>D</varname>,
|
<emphasis>deleted</emphasis>. Specifically, this acts on all files and directories marked with
|
||||||
|
<varname>f</varname>, <varname>F</varname>, <varname>d</varname>, <varname>D</varname>,
|
||||||
<varname>v</varname>, <varname>q</varname>, <varname>Q</varname>, <varname>p</varname>,
|
<varname>v</varname>, <varname>q</varname>, <varname>Q</varname>, <varname>p</varname>,
|
||||||
<varname>L</varname>, <varname>c</varname>, <varname>b</varname>, <varname>C</varname>,
|
<varname>L</varname>, <varname>c</varname>, <varname>b</varname>, <varname>C</varname>,
|
||||||
<varname>w</varname>, <varname>e</varname>. If this switch is used at least one
|
<varname>w</varname>, <varname>e</varname>. If this switch is used at least one
|
||||||
|
|
|
@ -539,6 +539,10 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
|
||||||
service, the line is silently skipped. If <literal>^</literal> and <literal>~</literal> are combined
|
service, the line is silently skipped. If <literal>^</literal> and <literal>~</literal> are combined
|
||||||
Base64 decoding is applied to the credential contents.</para>
|
Base64 decoding is applied to the credential contents.</para>
|
||||||
|
|
||||||
|
<para>If the dollar sign (<literal>$</literal>) is used, the file becomes subject to removal when
|
||||||
|
<command>systemd-tmpfiles</command> is invoked with the <option>--purge</option> switch. Lines without
|
||||||
|
this character are unaffected by that switch.</para>
|
||||||
|
|
||||||
<para>Note that for all line types that result in creation of any kind of file node
|
<para>Note that for all line types that result in creation of any kind of file node
|
||||||
(i.e. <varname>f</varname>,
|
(i.e. <varname>f</varname>,
|
||||||
<varname>d</varname>/<varname>D</varname>/<varname>v</varname>/<varname>q</varname>/<varname>Q</varname>,
|
<varname>d</varname>/<varname>D</varname>/<varname>v</varname>/<varname>q</varname>/<varname>Q</varname>,
|
||||||
|
|
|
@ -141,6 +141,12 @@
|
||||||
For example, e"string\n" is parsed as 7 characters: 6 lowercase letters and a newline.
|
For example, e"string\n" is parsed as 7 characters: 6 lowercase letters and a newline.
|
||||||
This can be useful for writing special characters when a kernel driver requires them.</para>
|
This can be useful for writing special characters when a kernel driver requires them.</para>
|
||||||
|
|
||||||
|
<para>The string can be prefixed with a lowercase i (i"string") to mark that the string or pattern
|
||||||
|
will match case-insensitively. For example, i"foo" will match
|
||||||
|
<literal>foo</literal>, <literal>FOO</literal>, <literal>FoO</literal> and so on. The prefix can be
|
||||||
|
used only for match (<literal>==</literal>) or unmatch (<literal>!=</literal>) rules, e.g.
|
||||||
|
<varname>ATTR{foo}==i"abcd"</varname>.</para>
|
||||||
|
|
||||||
<para>Please note that <constant>NUL</constant> is not allowed in either string variant.</para>
|
<para>Please note that <constant>NUL</constant> is not allowed in either string variant.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -221,6 +221,12 @@ const char* const systemd_features =
|
||||||
" -BPF_FRAMEWORK"
|
" -BPF_FRAMEWORK"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_VMLINUX_H
|
||||||
|
" +BTF"
|
||||||
|
#else
|
||||||
|
" -BTF"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if HAVE_XKBCOMMON
|
#if HAVE_XKBCOMMON
|
||||||
" +XKBCOMMON"
|
" +XKBCOMMON"
|
||||||
#else
|
#else
|
||||||
|
@ -247,7 +253,7 @@ const char* const systemd_features =
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
static char *systemd_features_with_color(void) {
|
static char* systemd_features_with_color(void) {
|
||||||
const char *p = systemd_features;
|
const char *p = systemd_features;
|
||||||
_cleanup_free_ char *ret = NULL;
|
_cleanup_free_ char *ret = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
|
@ -145,8 +145,10 @@ int efi_get_variable(
|
||||||
int efi_get_variable_string(const char *variable, char **ret) {
|
int efi_get_variable_string(const char *variable, char **ret) {
|
||||||
_cleanup_free_ void *s = NULL;
|
_cleanup_free_ void *s = NULL;
|
||||||
size_t ss = 0;
|
size_t ss = 0;
|
||||||
int r;
|
|
||||||
char *x;
|
char *x;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(variable);
|
||||||
|
|
||||||
r = efi_get_variable(variable, NULL, &s, &ss);
|
r = efi_get_variable(variable, NULL, &s, &ss);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -156,10 +158,27 @@ int efi_get_variable_string(const char *variable, char **ret) {
|
||||||
if (!x)
|
if (!x)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
*ret = x;
|
if (ret)
|
||||||
|
*ret = x;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int efi_get_variable_path(const char *variable, char **ret) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(variable);
|
||||||
|
|
||||||
|
r = efi_get_variable_string(variable, ret);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
efi_tilt_backslashes(*ret);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static int efi_verify_variable(const char *variable, uint32_t attr, const void *value, size_t size) {
|
static int efi_verify_variable(const char *variable, uint32_t attr, const void *value, size_t size) {
|
||||||
_cleanup_free_ void *buf = NULL;
|
_cleanup_free_ void *buf = NULL;
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "sd-id128.h"
|
#include "sd-id128.h"
|
||||||
|
|
||||||
#include "efivars-fundamental.h"
|
#include "efivars-fundamental.h"
|
||||||
|
#include "string-util.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
|
#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
|
||||||
|
@ -47,6 +48,7 @@
|
||||||
|
|
||||||
int efi_get_variable(const char *variable, uint32_t *attribute, void **ret_value, size_t *ret_size);
|
int efi_get_variable(const char *variable, uint32_t *attribute, void **ret_value, size_t *ret_size);
|
||||||
int efi_get_variable_string(const char *variable, char **ret);
|
int efi_get_variable_string(const char *variable, char **ret);
|
||||||
|
int efi_get_variable_path(const char *variable, char **ret);
|
||||||
int efi_set_variable(const char *variable, const void *value, size_t size);
|
int efi_set_variable(const char *variable, const void *value, size_t size);
|
||||||
int efi_set_variable_string(const char *variable, const char *p);
|
int efi_set_variable_string(const char *variable, const char *p);
|
||||||
|
|
||||||
|
@ -68,6 +70,10 @@ static inline int efi_get_variable_string(const char *variable, char **ret) {
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int efi_get_variable_path(const char *variable, char **ret) {
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int efi_set_variable(const char *variable, const void *value, size_t size) {
|
static inline int efi_set_variable(const char *variable, const void *value, size_t size) {
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
@ -100,3 +106,7 @@ static inline int systemd_efi_options_efivarfs_if_newer(char **line) {
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline char *efi_tilt_backslashes(char *s) {
|
||||||
|
return string_replace_char(s, '\\', '/');
|
||||||
|
}
|
||||||
|
|
|
@ -219,14 +219,12 @@ static int acquire_boot_count_path(
|
||||||
uint64_t left, done;
|
uint64_t left, done;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderBootCountPath), &path);
|
r = efi_get_variable_path(EFI_LOADER_VARIABLE(LoaderBootCountPath), &path);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
return -EUNATCH; /* in this case, let the caller print a message */
|
return -EUNATCH; /* in this case, let the caller print a message */
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read LoaderBootCountPath EFI variable: %m");
|
return log_error_errno(r, "Failed to read LoaderBootCountPath EFI variable: %m");
|
||||||
|
|
||||||
efi_tilt_backslashes(path);
|
|
||||||
|
|
||||||
if (!path_is_normalized(path))
|
if (!path_is_normalized(path))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Path read from LoaderBootCountPath is not normalized, refusing: %s",
|
"Path read from LoaderBootCountPath is not normalized, refusing: %s",
|
||||||
|
|
|
@ -298,12 +298,24 @@ fail:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_efi_var(const char *variable, char **ret) {
|
static int efi_get_variable_string_and_warn(const char *variable, char **ret) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = efi_get_variable_string(variable, ret);
|
r = efi_get_variable_string(variable, ret);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
log_warning_errno(r, "Failed to read EFI variable %s: %m", variable);
|
return log_warning_errno(r, "Failed to read EFI variable '%s', ignoring: %m", variable);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efi_get_variable_path_and_warn(const char *variable, char **ret) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = efi_get_variable_path(variable, ret);
|
||||||
|
if (r < 0 && r != -ENOENT)
|
||||||
|
return log_warning_errno(r, "Failed to read EFI variable '%s', ignoring: %m", variable);
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_yes_no_line(bool first, bool good, const char *name) {
|
static void print_yes_no_line(bool first, bool good, const char *name) {
|
||||||
|
@ -396,26 +408,23 @@ int verb_status(int argc, char *argv[], void *userdata) {
|
||||||
{ EFI_STUB_FEATURE_MULTI_PROFILE_UKI, "Stub understands profile selector" },
|
{ EFI_STUB_FEATURE_MULTI_PROFILE_UKI, "Stub understands profile selector" },
|
||||||
{ EFI_STUB_FEATURE_REPORT_STUB_PARTITION, "Stub sets stub partition information" },
|
{ EFI_STUB_FEATURE_REPORT_STUB_PARTITION, "Stub sets stub partition information" },
|
||||||
};
|
};
|
||||||
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
|
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL, *stub_path = NULL,
|
||||||
sd_id128_t loader_part_uuid = SD_ID128_NULL;
|
*current_entry = NULL, *oneshot_entry = NULL, *default_entry = NULL;
|
||||||
uint64_t loader_features = 0, stub_features = 0;
|
uint64_t loader_features = 0, stub_features = 0;
|
||||||
Tpm2Support s;
|
Tpm2Support s;
|
||||||
int have;
|
int have;
|
||||||
|
|
||||||
read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
|
||||||
read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareInfo), &fw_info);
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareInfo), &fw_info);
|
||||||
read_efi_var(EFI_LOADER_VARIABLE(LoaderInfo), &loader);
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderInfo), &loader);
|
||||||
read_efi_var(EFI_LOADER_VARIABLE(StubInfo), &stub);
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(StubInfo), &stub);
|
||||||
read_efi_var(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &loader_path);
|
(void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &loader_path);
|
||||||
|
(void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE(StubImageIdentifier), &stub_path);
|
||||||
(void) efi_loader_get_features(&loader_features);
|
(void) efi_loader_get_features(&loader_features);
|
||||||
(void) efi_stub_get_features(&stub_features);
|
(void) efi_stub_get_features(&stub_features);
|
||||||
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntrySelected), ¤t_entry);
|
||||||
if (loader_path)
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntryOneShot), &oneshot_entry);
|
||||||
efi_tilt_backslashes(loader_path);
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntryDefault), &default_entry);
|
||||||
|
|
||||||
k = efi_loader_get_device_part_uuid(&loader_part_uuid);
|
|
||||||
if (k < 0 && k != -ENOENT)
|
|
||||||
r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
|
|
||||||
|
|
||||||
SecureBootMode secure = efi_get_secure_boot_mode();
|
SecureBootMode secure = efi_get_secure_boot_mode();
|
||||||
printf("%sSystem:%s\n", ansi_underline(), ansi_normal());
|
printf("%sSystem:%s\n", ansi_underline(), ansi_normal());
|
||||||
|
@ -463,34 +472,58 @@ int verb_status(int argc, char *argv[], void *userdata) {
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
|
if (loader) {
|
||||||
printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader), ansi_normal());
|
printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
|
||||||
|
printf(" Product: %s%s%s\n", ansi_highlight(), loader, ansi_normal());
|
||||||
|
for (size_t i = 0; i < ELEMENTSOF(loader_flags); i++)
|
||||||
|
print_yes_no_line(i == 0, FLAGS_SET(loader_features, loader_flags[i].flag), loader_flags[i].name);
|
||||||
|
|
||||||
for (size_t i = 0; i < ELEMENTSOF(loader_flags); i++)
|
sd_id128_t loader_partition_uuid;
|
||||||
print_yes_no_line(i == 0, FLAGS_SET(loader_features, loader_flags[i].flag), loader_flags[i].name);
|
bool have_loader_partition_uuid = efi_loader_get_device_part_uuid(&loader_partition_uuid) >= 0;
|
||||||
|
|
||||||
sd_id128_t bootloader_esp_uuid;
|
print_yes_no_line(false, have_loader_partition_uuid, "Boot loader set ESP information");
|
||||||
bool have_bootloader_esp_uuid = efi_loader_get_device_part_uuid(&bootloader_esp_uuid) >= 0;
|
|
||||||
|
|
||||||
print_yes_no_line(false, have_bootloader_esp_uuid, "Boot loader sets ESP information");
|
if (current_entry)
|
||||||
if (have_bootloader_esp_uuid && !sd_id128_is_null(esp_uuid) &&
|
printf("Current Entry: %s\n", current_entry);
|
||||||
!sd_id128_equal(esp_uuid, bootloader_esp_uuid))
|
if (default_entry)
|
||||||
printf("WARNING: The boot loader reports a different ESP UUID than detected ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR")!\n",
|
printf("Default Entry: %s\n", default_entry);
|
||||||
SD_ID128_FORMAT_VAL(bootloader_esp_uuid),
|
if (oneshot_entry && !streq_ptr(oneshot_entry, default_entry))
|
||||||
SD_ID128_FORMAT_VAL(esp_uuid));
|
printf("OneShot Entry: %s\n", oneshot_entry);
|
||||||
|
|
||||||
|
if (have_loader_partition_uuid && !sd_id128_is_null(esp_uuid) && !sd_id128_equal(esp_uuid, loader_partition_uuid))
|
||||||
|
printf("WARNING: The boot loader reports a different partition UUID than the detected ESP ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR")!\n",
|
||||||
|
SD_ID128_FORMAT_VAL(loader_partition_uuid), SD_ID128_FORMAT_VAL(esp_uuid));
|
||||||
|
|
||||||
|
if (!sd_id128_is_null(loader_partition_uuid))
|
||||||
|
printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
||||||
|
SD_ID128_FORMAT_VAL(loader_partition_uuid));
|
||||||
|
else
|
||||||
|
printf(" Partition: n/a\n");
|
||||||
|
printf(" Loader: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path));
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (stub) {
|
if (stub) {
|
||||||
printf(" Stub: %s\n", stub);
|
printf("%sCurrent Stub:%s\n", ansi_underline(), ansi_normal());
|
||||||
|
printf(" Product: %s%s%s\n", ansi_highlight(), stub, ansi_normal());
|
||||||
for (size_t i = 0; i < ELEMENTSOF(stub_flags); i++)
|
for (size_t i = 0; i < ELEMENTSOF(stub_flags); i++)
|
||||||
print_yes_no_line(i == 0, FLAGS_SET(stub_features, stub_flags[i].flag), stub_flags[i].name);
|
print_yes_no_line(i == 0, FLAGS_SET(stub_features, stub_flags[i].flag), stub_flags[i].name);
|
||||||
|
|
||||||
|
sd_id128_t stub_partition_uuid;
|
||||||
|
bool have_stub_partition_uuid = efi_stub_get_device_part_uuid(&stub_partition_uuid) >= 0;
|
||||||
|
|
||||||
|
if (have_stub_partition_uuid && (!(!sd_id128_is_null(esp_uuid) && sd_id128_equal(esp_uuid, stub_partition_uuid)) &&
|
||||||
|
!(!sd_id128_is_null(xbootldr_uuid) && sd_id128_equal(xbootldr_uuid, stub_partition_uuid))))
|
||||||
|
printf("WARNING: The stub loader reports a different UUID than the detected ESP or XBOOTDLR partition ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR"/"SD_ID128_UUID_FORMAT_STR")!\n",
|
||||||
|
SD_ID128_FORMAT_VAL(stub_partition_uuid), SD_ID128_FORMAT_VAL(esp_uuid), SD_ID128_FORMAT_VAL(xbootldr_uuid));
|
||||||
|
if (!sd_id128_is_null(stub_partition_uuid))
|
||||||
|
printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
||||||
|
SD_ID128_FORMAT_VAL(stub_partition_uuid));
|
||||||
|
else
|
||||||
|
printf(" Partition: n/a\n");
|
||||||
|
printf(" Stub: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(stub_path));
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
if (!sd_id128_is_null(loader_part_uuid))
|
|
||||||
printf(" ESP: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
|
||||||
SD_ID128_FORMAT_VAL(loader_part_uuid));
|
|
||||||
else
|
|
||||||
printf(" ESP: n/a\n");
|
|
||||||
printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path));
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
|
printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
|
||||||
have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), F_OK) >= 0;
|
have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), F_OK) >= 0;
|
||||||
|
|
|
@ -16,12 +16,14 @@
|
||||||
#include "build.h"
|
#include "build.h"
|
||||||
#include "devnum-util.h"
|
#include "devnum-util.h"
|
||||||
#include "dissect-image.h"
|
#include "dissect-image.h"
|
||||||
|
#include "efi-loader.h"
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "find-esp.h"
|
#include "find-esp.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "mount-util.h"
|
#include "mount-util.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
|
#include "path-util.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
#include "varlink-io.systemd.BootControl.h"
|
#include "varlink-io.systemd.BootControl.h"
|
||||||
|
@ -38,6 +40,8 @@ char *arg_esp_path = NULL;
|
||||||
char *arg_xbootldr_path = NULL;
|
char *arg_xbootldr_path = NULL;
|
||||||
bool arg_print_esp_path = false;
|
bool arg_print_esp_path = false;
|
||||||
bool arg_print_dollar_boot_path = false;
|
bool arg_print_dollar_boot_path = false;
|
||||||
|
bool arg_print_loader_path = false;
|
||||||
|
bool arg_print_stub_path = false;
|
||||||
unsigned arg_print_root_device = 0;
|
unsigned arg_print_root_device = 0;
|
||||||
bool arg_touch_variables = true;
|
bool arg_touch_variables = true;
|
||||||
bool arg_install_random_seed = true;
|
bool arg_install_random_seed = true;
|
||||||
|
@ -133,6 +137,71 @@ int acquire_xbootldr(
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int print_loader_or_stub_path(void) {
|
||||||
|
_cleanup_free_ char *p = NULL;
|
||||||
|
sd_id128_t uuid;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (arg_print_loader_path) {
|
||||||
|
r = efi_loader_get_device_part_uuid(&uuid);
|
||||||
|
if (r == -ENOENT)
|
||||||
|
return log_error_errno(r, "No loader partition UUID passed.");
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Unable to determine loader partition UUID: %m");
|
||||||
|
|
||||||
|
r = efi_get_variable_path(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &p);
|
||||||
|
if (r == -ENOENT)
|
||||||
|
return log_error_errno(r, "No loader EFI binary path passed.");
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Unable to determine loader EFI binary path: %m");
|
||||||
|
} else {
|
||||||
|
assert(arg_print_stub_path);
|
||||||
|
|
||||||
|
r = efi_stub_get_device_part_uuid(&uuid);
|
||||||
|
if (r == -ENOENT)
|
||||||
|
return log_error_errno(r, "No stub partition UUID passed.");
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Unable to determine stub partition UUID: %m");
|
||||||
|
|
||||||
|
r = efi_get_variable_path(EFI_LOADER_VARIABLE(StubImageIdentifier), &p);
|
||||||
|
if (r == -ENOENT)
|
||||||
|
return log_error_errno(r, "No stub EFI binary path passed.");
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Unable to determine stub EFI binary path: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
sd_id128_t esp_uuid;
|
||||||
|
r = acquire_esp(/* unprivileged_mode= */ false, /* graceful= */ false,
|
||||||
|
/* ret_part= */ NULL, /* ret_pstart= */ NULL, /* ret_psize= */ NULL,
|
||||||
|
&esp_uuid, /* ret_devid= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
const char *found_path = NULL;
|
||||||
|
if (sd_id128_equal(esp_uuid, uuid))
|
||||||
|
found_path = arg_esp_path;
|
||||||
|
else if (arg_print_stub_path) { /* In case of the stub, also look for things in the xbootldr partition */
|
||||||
|
sd_id128_t xbootldr_uuid;
|
||||||
|
|
||||||
|
r = acquire_xbootldr(/* unprivileged_mode= */ false, &xbootldr_uuid, /* ret_devid= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (sd_id128_equal(xbootldr_uuid, uuid))
|
||||||
|
found_path = arg_xbootldr_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_path)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Failed to discover partition " SD_ID128_FORMAT_STR " among mounted boot partitions.", SD_ID128_FORMAT_VAL(uuid));
|
||||||
|
|
||||||
|
_cleanup_free_ char *j = path_join(found_path, p);
|
||||||
|
if (!j)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
puts(j);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int help(int argc, char *argv[], void *userdata) {
|
static int help(int argc, char *argv[], void *userdata) {
|
||||||
_cleanup_free_ char *link = NULL;
|
_cleanup_free_ char *link = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
@ -182,6 +251,9 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||||
" Where to pick files when using --root=/--image=\n"
|
" Where to pick files when using --root=/--image=\n"
|
||||||
" -p --print-esp-path Print path to the EFI System Partition mount point\n"
|
" -p --print-esp-path Print path to the EFI System Partition mount point\n"
|
||||||
" -x --print-boot-path Print path to the $BOOT partition mount point\n"
|
" -x --print-boot-path Print path to the $BOOT partition mount point\n"
|
||||||
|
" --print-loader-path\n"
|
||||||
|
" Print path to currently booted boot loader binary\n"
|
||||||
|
" --print-stub-path Print path to currently booted unified kernel binary\n"
|
||||||
" -R --print-root-device\n"
|
" -R --print-root-device\n"
|
||||||
" Print path to the block device node backing the\n"
|
" Print path to the block device node backing the\n"
|
||||||
" root file system (returns e.g. /dev/nvme0n1p5)\n"
|
" root file system (returns e.g. /dev/nvme0n1p5)\n"
|
||||||
|
@ -235,6 +307,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
ARG_ARCH_ALL,
|
ARG_ARCH_ALL,
|
||||||
ARG_EFI_BOOT_OPTION_DESCRIPTION,
|
ARG_EFI_BOOT_OPTION_DESCRIPTION,
|
||||||
ARG_DRY_RUN,
|
ARG_DRY_RUN,
|
||||||
|
ARG_PRINT_LOADER_PATH,
|
||||||
|
ARG_PRINT_STUB_PATH,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
|
@ -250,6 +324,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
{ "print-esp-path", no_argument, NULL, 'p' },
|
{ "print-esp-path", no_argument, NULL, 'p' },
|
||||||
{ "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */
|
{ "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */
|
||||||
{ "print-boot-path", no_argument, NULL, 'x' },
|
{ "print-boot-path", no_argument, NULL, 'x' },
|
||||||
|
{ "print-loader-path", no_argument, NULL, ARG_PRINT_LOADER_PATH },
|
||||||
|
{ "print-stub-path", no_argument, NULL, ARG_PRINT_STUB_PATH },
|
||||||
{ "print-root-device", no_argument, NULL, 'R' },
|
{ "print-root-device", no_argument, NULL, 'R' },
|
||||||
{ "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
|
{ "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
|
||||||
{ "random-seed", required_argument, NULL, ARG_RANDOM_SEED },
|
{ "random-seed", required_argument, NULL, ARG_RANDOM_SEED },
|
||||||
|
@ -332,6 +408,14 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
arg_print_dollar_boot_path = true;
|
arg_print_dollar_boot_path = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_PRINT_LOADER_PATH:
|
||||||
|
arg_print_loader_path = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_PRINT_STUB_PATH:
|
||||||
|
arg_print_stub_path = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'R':
|
case 'R':
|
||||||
arg_print_root_device++;
|
arg_print_root_device++;
|
||||||
break;
|
break;
|
||||||
|
@ -414,9 +498,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert_not_reached();
|
assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!!arg_print_esp_path + !!arg_print_dollar_boot_path + (arg_print_root_device > 0) > 1)
|
if (!!arg_print_esp_path + !!arg_print_dollar_boot_path + (arg_print_root_device > 0) + arg_print_loader_path + arg_print_stub_path > 1)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"--print-esp-path/-p, --print-boot-path/-x, --print-root-device=/-R cannot be combined.");
|
"--print-esp-path/-p, --print-boot-path/-x, --print-root-device=/-R, --print-loader-path, --print-stub-path cannot be combined.");
|
||||||
|
|
||||||
if ((arg_root || arg_image) && argv[optind] && !STR_IN_SET(argv[optind], "status", "list",
|
if ((arg_root || arg_image) && argv[optind] && !STR_IN_SET(argv[optind], "status", "list",
|
||||||
"install", "update", "remove", "is-installed", "random-seed", "unlink", "cleanup"))
|
"install", "update", "remove", "is-installed", "random-seed", "unlink", "cleanup"))
|
||||||
|
@ -541,6 +625,9 @@ static int run(int argc, char *argv[]) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg_print_loader_path || arg_print_stub_path)
|
||||||
|
return print_loader_or_stub_path();
|
||||||
|
|
||||||
/* Open up and mount the image */
|
/* Open up and mount the image */
|
||||||
if (arg_image) {
|
if (arg_image) {
|
||||||
assert(!arg_root);
|
assert(!arg_root);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -1046,7 +1046,6 @@ static int process_socket(int fd) {
|
||||||
_cleanup_close_ int input_fd = -EBADF, mount_tree_fd = -EBADF;
|
_cleanup_close_ int input_fd = -EBADF, mount_tree_fd = -EBADF;
|
||||||
Context context = {};
|
Context context = {};
|
||||||
struct iovec_wrapper iovw = {};
|
struct iovec_wrapper iovw = {};
|
||||||
struct iovec iovec;
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -1063,8 +1062,7 @@ static int process_socket(int fd) {
|
||||||
.msg_controllen = sizeof(control),
|
.msg_controllen = sizeof(control),
|
||||||
.msg_iovlen = 1,
|
.msg_iovlen = 1,
|
||||||
};
|
};
|
||||||
ssize_t n;
|
ssize_t n, l;
|
||||||
ssize_t l;
|
|
||||||
|
|
||||||
l = next_datagram_size_fd(fd);
|
l = next_datagram_size_fd(fd);
|
||||||
if (l < 0) {
|
if (l < 0) {
|
||||||
|
@ -1072,8 +1070,10 @@ static int process_socket(int fd) {
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
iovec.iov_len = l;
|
_cleanup_(iovec_done) struct iovec iovec = {
|
||||||
iovec.iov_base = malloc(l + 1);
|
.iov_len = l,
|
||||||
|
.iov_base = malloc(l + 1),
|
||||||
|
};
|
||||||
if (!iovec.iov_base) {
|
if (!iovec.iov_base) {
|
||||||
r = log_oom();
|
r = log_oom();
|
||||||
goto finish;
|
goto finish;
|
||||||
|
@ -1083,7 +1083,6 @@ static int process_socket(int fd) {
|
||||||
|
|
||||||
n = recvmsg_safe(fd, &mh, MSG_CMSG_CLOEXEC);
|
n = recvmsg_safe(fd, &mh, MSG_CMSG_CLOEXEC);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
free(iovec.iov_base);
|
|
||||||
r = log_error_errno(n, "Failed to receive datagram: %m");
|
r = log_error_errno(n, "Failed to receive datagram: %m");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
@ -1093,8 +1092,6 @@ static int process_socket(int fd) {
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
struct cmsghdr *found;
|
struct cmsghdr *found;
|
||||||
|
|
||||||
free(iovec.iov_base);
|
|
||||||
|
|
||||||
found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int) * 2));
|
found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int) * 2));
|
||||||
if (found) {
|
if (found) {
|
||||||
int fds[2] = EBADF_PAIR;
|
int fds[2] = EBADF_PAIR;
|
||||||
|
@ -1134,6 +1131,8 @@ static int process_socket(int fd) {
|
||||||
r = iovw_put(&iovw, iovec.iov_base, iovec.iov_len);
|
r = iovw_put(&iovw, iovec.iov_base, iovec.iov_len);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
TAKE_STRUCT(iovec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure we got all data we really need */
|
/* Make sure we got all data we really need */
|
||||||
|
|
|
@ -5602,7 +5602,7 @@ static int run_container(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: we do not use SD_EVENT_SIGNAL_PROCMASK or sd_event_set_signal_exit(), since we want the
|
/* Note: we do not use SD_EVENT_SIGNAL_PROCMASK or sd_event_set_signal_exit(), since we want the
|
||||||
* signals to be block continously, even if we destroy the event loop and allocate a new one on
|
* signals to be block continuously, even if we destroy the event loop and allocate a new one on
|
||||||
* container reboot. */
|
* container reboot. */
|
||||||
|
|
||||||
if (arg_kill_signal > 0) {
|
if (arg_kill_signal > 0) {
|
||||||
|
|
|
@ -5408,7 +5408,7 @@ static int partition_populate_directory(Context *context, Partition *p, char **r
|
||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
log_info("Populating %s filesystem.", p->format);
|
log_info("Preparing to populate %s filesystem.", p->format);
|
||||||
|
|
||||||
r = var_tmp_dir(&vt);
|
r = var_tmp_dir(&vt);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -5434,7 +5434,7 @@ static int partition_populate_directory(Context *context, Partition *p, char **r
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
log_info("Successfully populated %s filesystem.", p->format);
|
log_info("Ready to populate %s filesystem.", p->format);
|
||||||
|
|
||||||
*ret = TAKE_PTR(root);
|
*ret = TAKE_PTR(root);
|
||||||
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,34 @@ 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) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (FLAGS_SET(flags, ASK_PASSWORD_USER))
|
||||||
|
return acquire_user_ask_password_directory(ret);
|
||||||
|
|
||||||
|
r = strdup_to(ret, "/run/systemd/ask-password/");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 1; /* there's a suitable directory known to us */
|
||||||
|
}
|
||||||
|
|
||||||
|
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 +137,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 +159,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 +250,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 +270,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 +296,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 +313,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 +321,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 +413,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 +435,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 +509,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 +531,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 +541,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 +699,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 +740,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 +766,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 +789,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 +815,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 +847,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 +883,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 +893,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 +911,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 +959,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 +999,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 +1069,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);
|
||||||
|
|
|
@ -66,9 +66,5 @@ static inline bool efi_has_tpm2(void) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline char *efi_tilt_backslashes(char *s) {
|
|
||||||
return string_replace_char(s, '\\', '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
sd_id128_t efi_guid_to_id128(const void *guid);
|
sd_id128_t efi_guid_to_id128(const void *guid);
|
||||||
void efi_id128_to_guid(sd_id128_t id, void *ret_guid);
|
void efi_id128_to_guid(sd_id128_t id, void *ret_guid);
|
||||||
|
|
|
@ -61,30 +61,19 @@ int efi_loader_get_boot_usec(usec_t *ret_firmware, usec_t *ret_loader) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int efi_loader_get_device_part_uuid(sd_id128_t *ret) {
|
static int get_device_part_uuid(const char *variable, sd_id128_t *ret) {
|
||||||
_cleanup_free_ char *p = NULL;
|
|
||||||
int r;
|
|
||||||
unsigned parsed[16];
|
|
||||||
|
|
||||||
if (!is_efi_boot())
|
if (!is_efi_boot())
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderDevicePartUUID), &p);
|
return efi_get_variable_id128(variable, ret);
|
||||||
if (r < 0)
|
}
|
||||||
return r;
|
|
||||||
|
|
||||||
if (sscanf(p, SD_ID128_UUID_FORMAT_STR,
|
int efi_loader_get_device_part_uuid(sd_id128_t *ret) {
|
||||||
&parsed[0], &parsed[1], &parsed[2], &parsed[3],
|
return get_device_part_uuid(EFI_LOADER_VARIABLE(LoaderDevicePartUUID), ret);
|
||||||
&parsed[4], &parsed[5], &parsed[6], &parsed[7],
|
}
|
||||||
&parsed[8], &parsed[9], &parsed[10], &parsed[11],
|
|
||||||
&parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
if (ret)
|
int efi_stub_get_device_part_uuid(sd_id128_t *ret) {
|
||||||
for (unsigned i = 0; i < ELEMENTSOF(parsed); i++)
|
return get_device_part_uuid(EFI_LOADER_VARIABLE(StubDevicePartUUID), ret);
|
||||||
ret->bytes[i] = parsed[i];
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int efi_loader_get_entries(char ***ret) {
|
int efi_loader_get_entries(char ***ret) {
|
||||||
|
@ -353,6 +342,22 @@ int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int efi_get_variable_id128(const char *variable, sd_id128_t *ret) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(variable);
|
||||||
|
|
||||||
|
/* This is placed here (rather than in basic/efivars.c) because code in basic/ is not allowed to link
|
||||||
|
* against libsystemd.so */
|
||||||
|
|
||||||
|
_cleanup_free_ char *p = NULL;
|
||||||
|
r = efi_get_variable_string(variable, &p);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return sd_id128_from_string(p, ret);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool efi_loader_entry_name_valid(const char *s) {
|
bool efi_loader_entry_name_valid(const char *s) {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#if ENABLE_EFI
|
#if ENABLE_EFI
|
||||||
|
|
||||||
int efi_loader_get_device_part_uuid(sd_id128_t *ret);
|
int efi_loader_get_device_part_uuid(sd_id128_t *ret);
|
||||||
|
int efi_stub_get_device_part_uuid(sd_id128_t *ret);
|
||||||
int efi_loader_get_boot_usec(usec_t *ret_firmware, usec_t *ret_loader);
|
int efi_loader_get_boot_usec(usec_t *ret_firmware, usec_t *ret_loader);
|
||||||
|
|
||||||
int efi_loader_get_entries(char ***ret);
|
int efi_loader_get_entries(char ***ret);
|
||||||
|
@ -23,6 +24,8 @@ int efi_measured_uki(int log_level);
|
||||||
int efi_loader_get_config_timeout_one_shot(usec_t *ret);
|
int efi_loader_get_config_timeout_one_shot(usec_t *ret);
|
||||||
int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat);
|
int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat);
|
||||||
|
|
||||||
|
int efi_get_variable_id128(const char *variable, sd_id128_t *ret);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int efi_loader_get_device_part_uuid(sd_id128_t *u) {
|
static inline int efi_loader_get_device_part_uuid(sd_id128_t *u) {
|
||||||
|
@ -58,6 +61,10 @@ static inline int efi_loader_update_entry_one_shot_cache(char **cache, struct st
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int efi_get_variable_id128(const char *variable, sd_id128_t *ret) {
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool efi_loader_entry_name_valid(const char *s);
|
bool efi_loader_entry_name_valid(const char *s);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
static const char * const kernel_image_type_table[_KERNEL_IMAGE_TYPE_MAX] = {
|
static const char * const kernel_image_type_table[_KERNEL_IMAGE_TYPE_MAX] = {
|
||||||
[KERNEL_IMAGE_TYPE_UNKNOWN] = "unknown",
|
[KERNEL_IMAGE_TYPE_UNKNOWN] = "unknown",
|
||||||
[KERNEL_IMAGE_TYPE_UKI] = "uki",
|
[KERNEL_IMAGE_TYPE_UKI] = "uki",
|
||||||
|
[KERNEL_IMAGE_TYPE_ADDON] = "addon",
|
||||||
[KERNEL_IMAGE_TYPE_PE] = "pe",
|
[KERNEL_IMAGE_TYPE_PE] = "pe",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -159,6 +160,16 @@ int inspect_kernel(
|
||||||
|
|
||||||
t = KERNEL_IMAGE_TYPE_UKI;
|
t = KERNEL_IMAGE_TYPE_UKI;
|
||||||
goto done;
|
goto done;
|
||||||
|
} else if (pe_is_addon(pe_header, sections)) {
|
||||||
|
r = inspect_uki(fd, pe_header, sections, ret_cmdline, ret_uname, /* ret_pretty_name= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (ret_pretty_name)
|
||||||
|
*ret_pretty_name = NULL;
|
||||||
|
|
||||||
|
t = KERNEL_IMAGE_TYPE_ADDON;
|
||||||
|
goto done;
|
||||||
} else
|
} else
|
||||||
t = KERNEL_IMAGE_TYPE_PE;
|
t = KERNEL_IMAGE_TYPE_PE;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
typedef enum KernelImageType {
|
typedef enum KernelImageType {
|
||||||
KERNEL_IMAGE_TYPE_UNKNOWN,
|
KERNEL_IMAGE_TYPE_UNKNOWN,
|
||||||
KERNEL_IMAGE_TYPE_UKI,
|
KERNEL_IMAGE_TYPE_UKI,
|
||||||
|
KERNEL_IMAGE_TYPE_ADDON,
|
||||||
KERNEL_IMAGE_TYPE_PE,
|
KERNEL_IMAGE_TYPE_PE,
|
||||||
_KERNEL_IMAGE_TYPE_MAX,
|
_KERNEL_IMAGE_TYPE_MAX,
|
||||||
_KERNEL_IMAGE_TYPE_INVALID = -EINVAL,
|
_KERNEL_IMAGE_TYPE_INVALID = -EINVAL,
|
||||||
|
|
|
@ -170,6 +170,8 @@ typedef struct Item {
|
||||||
|
|
||||||
bool try_replace:1;
|
bool try_replace:1;
|
||||||
|
|
||||||
|
bool purge:1;
|
||||||
|
|
||||||
OperationMask done;
|
OperationMask done;
|
||||||
} Item;
|
} Item;
|
||||||
|
|
||||||
|
@ -3046,6 +3048,9 @@ static int purge_item(Context *c, Item *i) {
|
||||||
if (!needs_purge(i->type))
|
if (!needs_purge(i->type))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!i->purge)
|
||||||
|
return 0;
|
||||||
|
|
||||||
log_debug("Running purge action for entry %c %s", (char) i->type, i->path);
|
log_debug("Running purge action for entry %c %s", (char) i->type, i->path);
|
||||||
|
|
||||||
if (needs_glob(i->type))
|
if (needs_glob(i->type))
|
||||||
|
@ -3602,7 +3607,7 @@ static int parse_line(
|
||||||
ItemArray *existing;
|
ItemArray *existing;
|
||||||
OrderedHashmap *h;
|
OrderedHashmap *h;
|
||||||
bool append_or_force = false, boot = false, allow_failure = false, try_replace = false,
|
bool append_or_force = false, boot = false, allow_failure = false, try_replace = false,
|
||||||
unbase64 = false, from_cred = false, missing_user_or_group = false;
|
unbase64 = false, from_cred = false, missing_user_or_group = false, purge = false;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(fname);
|
assert(fname);
|
||||||
|
@ -3668,6 +3673,8 @@ static int parse_line(
|
||||||
unbase64 = true;
|
unbase64 = true;
|
||||||
else if (action[pos] == '^' && !from_cred)
|
else if (action[pos] == '^' && !from_cred)
|
||||||
from_cred = true;
|
from_cred = true;
|
||||||
|
else if (action[pos] == '$' && !purge)
|
||||||
|
purge = true;
|
||||||
else {
|
else {
|
||||||
*invalid_config = true;
|
*invalid_config = true;
|
||||||
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
|
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
|
||||||
|
@ -3684,6 +3691,7 @@ static int parse_line(
|
||||||
i.append_or_force = append_or_force;
|
i.append_or_force = append_or_force;
|
||||||
i.allow_failure = allow_failure;
|
i.allow_failure = allow_failure;
|
||||||
i.try_replace = try_replace;
|
i.try_replace = try_replace;
|
||||||
|
i.purge = purge;
|
||||||
|
|
||||||
r = specifier_printf(path, PATH_MAX-1, specifier_table, arg_root, NULL, &i.path);
|
r = specifier_printf(path, PATH_MAX-1, specifier_table, arg_root, NULL, &i.path);
|
||||||
if (ERRNO_IS_NOINFO(r))
|
if (ERRNO_IS_NOINFO(r))
|
||||||
|
@ -3838,6 +3846,12 @@ static int parse_line(
|
||||||
"Unknown command type '%c'.", (char) i.type);
|
"Unknown command type '%c'.", (char) i.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i.purge && !needs_purge(i.type)) {
|
||||||
|
*invalid_config = true;
|
||||||
|
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
|
||||||
|
"Purge flag '$' combined with line type '%c' which does not support purging.", (char) i.type);
|
||||||
|
}
|
||||||
|
|
||||||
if (!should_include_path(i.path))
|
if (!should_include_path(i.path))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -11,6 +11,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
int r;
|
int r;
|
||||||
char *value = UINT_TO_PTR(0x12345678U);
|
char *value = UINT_TO_PTR(0x12345678U);
|
||||||
char *endpos = UINT_TO_PTR(0x87654321U);
|
char *endpos = UINT_TO_PTR(0x87654321U);
|
||||||
|
bool is_case_sensitive;
|
||||||
|
|
||||||
fuzz_setup_logging();
|
fuzz_setup_logging();
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
memcpy(str, data, size);
|
memcpy(str, data, size);
|
||||||
str[size] = '\0';
|
str[size] = '\0';
|
||||||
|
|
||||||
r = udev_rule_parse_value(str, &value, &endpos);
|
r = udev_rule_parse_value(str, &value, &endpos, &is_case_sensitive);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
/* not modified on failure */
|
/* not modified on failure */
|
||||||
assert_se(value == UINT_TO_PTR(0x12345678U));
|
assert_se(value == UINT_TO_PTR(0x12345678U));
|
||||||
|
|
|
@ -4,15 +4,16 @@
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "udev-rules.h"
|
#include "udev-rules.h"
|
||||||
|
|
||||||
static void test_udev_rule_parse_value_one(const char *in, const char *expected_value, int expected_retval) {
|
static void test_udev_rule_parse_value_one(const char *in, const char *expected_value, bool expected_case_insensitive, int expected_retval) {
|
||||||
_cleanup_free_ char *str = NULL;
|
_cleanup_free_ char *str = NULL;
|
||||||
char *value = UINT_TO_PTR(0x12345678U);
|
char *value = UINT_TO_PTR(0x12345678U);
|
||||||
char *endpos = UINT_TO_PTR(0x87654321U);
|
char *endpos = UINT_TO_PTR(0x87654321U);
|
||||||
|
bool i;
|
||||||
|
|
||||||
log_info("/* %s (%s, %s, %d) */", __func__, in, strnull(expected_value), expected_retval);
|
log_info("/* %s (%s, %s, %d) */", __func__, in, strnull(expected_value), expected_retval);
|
||||||
|
|
||||||
assert_se(str = strdup(in));
|
assert_se(str = strdup(in));
|
||||||
assert_se(udev_rule_parse_value(str, &value, &endpos) == expected_retval);
|
assert_se(udev_rule_parse_value(str, &value, &endpos, &i) == expected_retval);
|
||||||
if (expected_retval < 0) {
|
if (expected_retval < 0) {
|
||||||
/* not modified on failure */
|
/* not modified on failure */
|
||||||
assert_se(value == UINT_TO_PTR(0x12345678U));
|
assert_se(value == UINT_TO_PTR(0x12345678U));
|
||||||
|
@ -25,6 +26,7 @@ static void test_udev_rule_parse_value_one(const char *in, const char *expected_
|
||||||
* so it could be safely interpreted as nulstr.
|
* so it could be safely interpreted as nulstr.
|
||||||
*/
|
*/
|
||||||
assert_se(value[strlen(value) + 1] == '\0');
|
assert_se(value[strlen(value) + 1] == '\0');
|
||||||
|
assert_se(i == expected_case_insensitive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,45 +35,61 @@ TEST(udev_rule_parse_value) {
|
||||||
* parsed: valid operand
|
* parsed: valid operand
|
||||||
* use the following command to help generate textual C strings:
|
* use the following command to help generate textual C strings:
|
||||||
* python3 -c 'import json; print(json.dumps(input()))' */
|
* python3 -c 'import json; print(json.dumps(input()))' */
|
||||||
test_udev_rule_parse_value_one("\"valid operand\"", "valid operand", 0);
|
test_udev_rule_parse_value_one("\"valid operand\"", "valid operand", /* case_insensitive = */ false, 0);
|
||||||
/* input: "va'l\'id\"op\"erand"
|
/* input: "va'l\'id\"op\"erand"
|
||||||
* parsed: va'l\'id"op"erand */
|
* parsed: va'l\'id"op"erand */
|
||||||
test_udev_rule_parse_value_one("\"va'l\\'id\\\"op\\\"erand\"", "va'l\\'id\"op\"erand", 0);
|
test_udev_rule_parse_value_one("\"va'l\\'id\\\"op\\\"erand\"", "va'l\\'id\"op\"erand", /* case_insensitive = */ false, 0);
|
||||||
test_udev_rule_parse_value_one("no quotes", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("no quotes", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
test_udev_rule_parse_value_one("\"\\\\a\\b\\x\\y\"", "\\\\a\\b\\x\\y", 0);
|
test_udev_rule_parse_value_one("\"\\\\a\\b\\x\\y\"", "\\\\a\\b\\x\\y", /* case_insensitive = */ false, 0);
|
||||||
test_udev_rule_parse_value_one("\"reject\0nul\"", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("\"reject\0nul\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
/* input: e"" */
|
/* input: e"" */
|
||||||
test_udev_rule_parse_value_one("e\"\"", "", 0);
|
test_udev_rule_parse_value_one("e\"\"", "", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"1234" */
|
/* input: e"1234" */
|
||||||
test_udev_rule_parse_value_one("e\"1234\"", "1234", 0);
|
test_udev_rule_parse_value_one("e\"1234\"", "1234", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"\"" */
|
/* input: e"\"" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\"\"", "\"", 0);
|
test_udev_rule_parse_value_one("e\"\\\"\"", "\"", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"\ */
|
/* input: e"\ */
|
||||||
test_udev_rule_parse_value_one("e\"\\", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("e\"\\", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
/* input: e"\" */
|
/* input: e"\" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\"", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("e\"\\\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
/* input: e"\\" */
|
/* input: e"\\" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\\\"", "\\", 0);
|
test_udev_rule_parse_value_one("e\"\\\\\"", "\\", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"\\\" */
|
/* input: e"\\\" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\\\\\"", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("e\"\\\\\\\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
/* input: e"\\\"" */
|
/* input: e"\\\"" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\\\\\"\"", "\\\"", 0);
|
test_udev_rule_parse_value_one("e\"\\\\\\\"\"", "\\\"", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"\\\\" */
|
/* input: e"\\\\" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\\\\\\\"", "\\\\", 0);
|
test_udev_rule_parse_value_one("e\"\\\\\\\\\"", "\\\\", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"operand with newline\n" */
|
/* input: e"operand with newline\n" */
|
||||||
test_udev_rule_parse_value_one("e\"operand with newline\\n\"", "operand with newline\n", 0);
|
test_udev_rule_parse_value_one("e\"operand with newline\\n\"", "operand with newline\n", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"single\rcharacter\t\aescape\bsequence" */
|
/* input: e"single\rcharacter\t\aescape\bsequence" */
|
||||||
test_udev_rule_parse_value_one(
|
test_udev_rule_parse_value_one(
|
||||||
"e\"single\\rcharacter\\t\\aescape\\bsequence\"", "single\rcharacter\t\aescape\bsequence", 0);
|
"e\"single\\rcharacter\\t\\aescape\\bsequence\"", "single\rcharacter\t\aescape\bsequence", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"reject\invalid escape sequence" */
|
/* input: e"reject\invalid escape sequence" */
|
||||||
test_udev_rule_parse_value_one("e\"reject\\invalid escape sequence", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("e\"reject\\invalid escape sequence", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
/* input: e"\ */
|
/* input: e"\ */
|
||||||
test_udev_rule_parse_value_one("e\"\\", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("e\"\\", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
/* input: "s\u1d1c\u1d04\u029c \u1d1c\u0274\u026a\u1d04\u1d0f\u1d05\u1d07 \U0001d568\U0001d560\U0001d568" */
|
/* input: "s\u1d1c\u1d04\u029c \u1d1c\u0274\u026a\u1d04\u1d0f\u1d05\u1d07 \U0001d568\U0001d560\U0001d568" */
|
||||||
test_udev_rule_parse_value_one(
|
test_udev_rule_parse_value_one(
|
||||||
"e\"s\\u1d1c\\u1d04\\u029c \\u1d1c\\u0274\\u026a\\u1d04\\u1d0f\\u1d05\\u1d07 \\U0001d568\\U0001d560\\U0001d568\"",
|
"e\"s\\u1d1c\\u1d04\\u029c \\u1d1c\\u0274\\u026a\\u1d04\\u1d0f\\u1d05\\u1d07 \\U0001d568\\U0001d560\\U0001d568\"",
|
||||||
"s\xe1\xb4\x9c\xe1\xb4\x84\xca\x9c \xe1\xb4\x9c\xc9\xb4\xc9\xaa\xe1\xb4\x84\xe1\xb4\x8f\xe1\xb4\x85\xe1\xb4\x87 \xf0\x9d\x95\xa8\xf0\x9d\x95\xa0\xf0\x9d\x95\xa8",
|
"s\xe1\xb4\x9c\xe1\xb4\x84\xca\x9c \xe1\xb4\x9c\xc9\xb4\xc9\xaa\xe1\xb4\x84\xe1\xb4\x8f\xe1\xb4\x85\xe1\xb4\x87 \xf0\x9d\x95\xa8\xf0\x9d\x95\xa0\xf0\x9d\x95\xa8",
|
||||||
0);
|
/* case_insensitive = */ false, 0);
|
||||||
|
/* input: i"ABCD1234" */
|
||||||
|
test_udev_rule_parse_value_one("i\"ABCD1234\"", "ABCD1234", /* case_insensitive = */ true, 0);
|
||||||
|
/* input: i"ABCD1234" */
|
||||||
|
test_udev_rule_parse_value_one("e\"ABCD1234\"", "ABCD1234", /* case_insensitive = */ false, 0);
|
||||||
|
/* input: ei"\\"ABCD1234 */
|
||||||
|
test_udev_rule_parse_value_one("ei\"\\\\ABCD1234\"", "\\ABCD1234", /* case_insensitive = */ true, 0);
|
||||||
|
/* input: ie"\\"ABCD1234 */
|
||||||
|
test_udev_rule_parse_value_one("ie\"\\\\ABCD1234\"", "\\ABCD1234", /* case_insensitive = */ true, 0);
|
||||||
|
/* input: i */
|
||||||
|
test_udev_rule_parse_value_one("i", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
|
/* input: ee"" */
|
||||||
|
test_udev_rule_parse_value_one("ee\"\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
|
/* input: iei"" */
|
||||||
|
test_udev_rule_parse_value_one("iei\"\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
|
/* input: a"" */
|
||||||
|
test_udev_rule_parse_value_one("a\"\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||||
|
|
|
@ -63,9 +63,15 @@ typedef enum {
|
||||||
MATCH_TYPE_GLOB_WITH_EMPTY, /* shell globs ?,*,[] with empty string, e.g., "|foo*" */
|
MATCH_TYPE_GLOB_WITH_EMPTY, /* shell globs ?,*,[] with empty string, e.g., "|foo*" */
|
||||||
MATCH_TYPE_SUBSYSTEM, /* "subsystem", "bus", or "class" */
|
MATCH_TYPE_SUBSYSTEM, /* "subsystem", "bus", or "class" */
|
||||||
_MATCH_TYPE_MAX,
|
_MATCH_TYPE_MAX,
|
||||||
_MATCH_TYPE_INVALID = -EINVAL,
|
|
||||||
|
_MATCH_TYPE_MASK = (1 << 5) - 1,
|
||||||
|
MATCH_REMOVE_TRAILING_WHITESPACE = 1 << 5, /* Remove trailing whitespaces in attribute */
|
||||||
|
MATCH_CASE_INSENSITIVE = 1 << 6, /* string or pattern is matched case-insensitively */
|
||||||
|
_MATCH_TYPE_INVALID = -EINVAL,
|
||||||
} UdevRuleMatchType;
|
} UdevRuleMatchType;
|
||||||
|
|
||||||
|
assert_cc(_MATCH_TYPE_MAX <= _MATCH_TYPE_MASK);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SUBST_TYPE_PLAIN, /* no substitution */
|
SUBST_TYPE_PLAIN, /* no substitution */
|
||||||
SUBST_TYPE_FORMAT, /* % or $ */
|
SUBST_TYPE_FORMAT, /* % or $ */
|
||||||
|
@ -155,8 +161,7 @@ struct UdevRuleToken {
|
||||||
UdevRuleTokenType type:8;
|
UdevRuleTokenType type:8;
|
||||||
UdevRuleOperatorType op:8;
|
UdevRuleOperatorType op:8;
|
||||||
UdevRuleMatchType match_type:8;
|
UdevRuleMatchType match_type:8;
|
||||||
UdevRuleSubstituteType attr_subst_type:7;
|
UdevRuleSubstituteType attr_subst_type:8;
|
||||||
bool attr_match_remove_trailing_whitespace:1;
|
|
||||||
const char *value;
|
const char *value;
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
|
@ -295,6 +300,7 @@ struct UdevRules {
|
||||||
|
|
||||||
#define log_line_invalid_op(line, key) _log_line_invalid_token(line, key, "operator")
|
#define log_line_invalid_op(line, key) _log_line_invalid_token(line, key, "operator")
|
||||||
#define log_line_invalid_attr(line, key) _log_line_invalid_token(line, key, "attribute")
|
#define log_line_invalid_attr(line, key) _log_line_invalid_token(line, key, "attribute")
|
||||||
|
#define log_line_invalid_prefix(line, key) _log_line_invalid_token(line, key, "prefix 'i'")
|
||||||
|
|
||||||
#define log_line_invalid_attr_format(line, key, attr, offset, hint) \
|
#define log_line_invalid_attr_format(line, key, attr, offset, hint) \
|
||||||
log_line_error_errno(line, SYNTHETIC_ERRNO(EINVAL), \
|
log_line_error_errno(line, SYNTHETIC_ERRNO(EINVAL), \
|
||||||
|
@ -488,12 +494,10 @@ static bool type_has_nulstr_value(UdevRuleTokenType type) {
|
||||||
return type < TK_M_TEST || type == TK_M_RESULT;
|
return type < TK_M_TEST || type == TK_M_RESULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type, UdevRuleOperatorType op, char *value, void *data) {
|
static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type, UdevRuleOperatorType op, char *value, void *data, bool is_case_insensitive) {
|
||||||
_cleanup_(udev_rule_token_freep) UdevRuleToken *token = NULL;
|
_cleanup_(udev_rule_token_freep) UdevRuleToken *token = NULL;
|
||||||
UdevRuleMatchType match_type = _MATCH_TYPE_INVALID;
|
UdevRuleMatchType match_type = _MATCH_TYPE_INVALID;
|
||||||
UdevRuleSubstituteType subst_type = _SUBST_TYPE_INVALID;
|
UdevRuleSubstituteType subst_type = _SUBST_TYPE_INVALID;
|
||||||
bool remove_trailing_whitespace = false;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
assert(rule_line);
|
assert(rule_line);
|
||||||
assert(type >= 0 && type < _TK_TYPE_MAX);
|
assert(type >= 0 && type < _TK_TYPE_MAX);
|
||||||
|
@ -552,16 +556,21 @@ static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IN_SET(type, TK_M_ATTR, TK_M_PARENTS_ATTR)) {
|
if (IN_SET(type, TK_M_ATTR, TK_M_PARENTS_ATTR)) {
|
||||||
|
size_t len;
|
||||||
|
|
||||||
assert(value);
|
assert(value);
|
||||||
assert(data);
|
assert(data);
|
||||||
|
assert(match_type >= 0 && match_type < _MATCH_TYPE_MAX);
|
||||||
|
|
||||||
len = strlen(value);
|
len = strlen(value);
|
||||||
if (len > 0 && !isspace(value[len - 1]))
|
if (len > 0 && !isspace(value[len - 1]))
|
||||||
remove_trailing_whitespace = true;
|
match_type |= MATCH_REMOVE_TRAILING_WHITESPACE;
|
||||||
|
|
||||||
subst_type = rule_get_substitution_type(data);
|
subst_type = rule_get_substitution_type(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SET_FLAG(match_type, MATCH_CASE_INSENSITIVE, is_case_insensitive);
|
||||||
|
|
||||||
token = new(UdevRuleToken, 1);
|
token = new(UdevRuleToken, 1);
|
||||||
if (!token)
|
if (!token)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -573,7 +582,6 @@ static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type,
|
||||||
.data = data,
|
.data = data,
|
||||||
.match_type = match_type,
|
.match_type = match_type,
|
||||||
.attr_subst_type = subst_type,
|
.attr_subst_type = subst_type,
|
||||||
.attr_match_remove_trailing_whitespace = remove_trailing_whitespace,
|
|
||||||
.rule_line = rule_line,
|
.rule_line = rule_line,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -621,7 +629,7 @@ static int check_attr_format_and_warn(UdevRuleLine *line, const char *key, const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, UdevRuleOperatorType op, char *value) {
|
static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, UdevRuleOperatorType op, char *value, bool is_case_insensitive) {
|
||||||
ResolveNameTiming resolve_name_timing = LINE_GET_RULES(rule_line)->resolve_name_timing;
|
ResolveNameTiming resolve_name_timing = LINE_GET_RULES(rule_line)->resolve_name_timing;
|
||||||
bool is_match = IN_SET(op, OP_MATCH, OP_NOMATCH);
|
bool is_match = IN_SET(op, OP_MATCH, OP_NOMATCH);
|
||||||
int r;
|
int r;
|
||||||
|
@ -629,35 +637,39 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
assert(key);
|
assert(key);
|
||||||
assert(value);
|
assert(value);
|
||||||
|
|
||||||
|
if (!is_match && is_case_insensitive)
|
||||||
|
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
||||||
|
"Invalid prefix 'i' for '%s'. The 'i' prefix can be specified only for '==' or '!=' operator.", key);
|
||||||
|
|
||||||
if (streq(key, "ACTION")) {
|
if (streq(key, "ACTION")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_ACTION, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_ACTION, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "DEVPATH")) {
|
} else if (streq(key, "DEVPATH")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_DEVPATH, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_DEVPATH, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "KERNEL")) {
|
} else if (streq(key, "KERNEL")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_KERNEL, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_KERNEL, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "SYMLINK")) {
|
} else if (streq(key, "SYMLINK")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match) {
|
if (!is_match) {
|
||||||
check_value_format_and_warn(rule_line, key, value, false);
|
check_value_format_and_warn(rule_line, key, value, false);
|
||||||
r = rule_line_add_token(rule_line, TK_A_DEVLINK, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_DEVLINK, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_DEVLINK, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_DEVLINK, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "NAME")) {
|
} else if (streq(key, "NAME")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
|
@ -677,9 +689,9 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
"Ignoring NAME=\"\", as udev will not delete any network interfaces.");
|
"Ignoring NAME=\"\", as udev will not delete any network interfaces.");
|
||||||
check_value_format_and_warn(rule_line, key, value, false);
|
check_value_format_and_warn(rule_line, key, value, false);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_A_NAME, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_NAME, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_NAME, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_NAME, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "ENV")) {
|
} else if (streq(key, "ENV")) {
|
||||||
if (isempty(attr))
|
if (isempty(attr))
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
|
@ -697,15 +709,15 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
|
|
||||||
check_value_format_and_warn(rule_line, key, value, false);
|
check_value_format_and_warn(rule_line, key, value, false);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_A_ENV, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_A_ENV, op, value, attr, /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_ENV, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_M_ENV, op, value, attr, is_case_insensitive);
|
||||||
} else if (streq(key, "CONST")) {
|
} else if (streq(key, "CONST")) {
|
||||||
if (isempty(attr) || !STR_IN_SET(attr, "arch", "virt"))
|
if (isempty(attr) || !STR_IN_SET(attr, "arch", "virt"))
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
r = rule_line_add_token(rule_line, TK_M_CONST, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_M_CONST, op, value, attr, is_case_insensitive);
|
||||||
} else if (streq(key, "TAG")) {
|
} else if (streq(key, "TAG")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
|
@ -717,9 +729,9 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (!is_match) {
|
if (!is_match) {
|
||||||
check_value_format_and_warn(rule_line, key, value, true);
|
check_value_format_and_warn(rule_line, key, value, true);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_A_TAG, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_TAG, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_TAG, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_TAG, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "SUBSYSTEM")) {
|
} else if (streq(key, "SUBSYSTEM")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
|
@ -729,14 +741,14 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (STR_IN_SET(value, "bus", "class"))
|
if (STR_IN_SET(value, "bus", "class"))
|
||||||
log_line_warning(rule_line, "\"%s\" must be specified as \"subsystem\".", value);
|
log_line_warning(rule_line, "\"%s\" must be specified as \"subsystem\".", value);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_SUBSYSTEM, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_SUBSYSTEM, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "DRIVER")) {
|
} else if (streq(key, "DRIVER")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_DRIVER, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_DRIVER, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "ATTR")) {
|
} else if (streq(key, "ATTR")) {
|
||||||
r = check_attr_format_and_warn(rule_line, key, attr);
|
r = check_attr_format_and_warn(rule_line, key, attr);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -750,9 +762,9 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
|
|
||||||
if (!is_match) {
|
if (!is_match) {
|
||||||
check_value_format_and_warn(rule_line, key, value, false);
|
check_value_format_and_warn(rule_line, key, value, false);
|
||||||
r = rule_line_add_token(rule_line, TK_A_ATTR, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_A_ATTR, op, value, attr, /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_ATTR, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_M_ATTR, op, value, attr, is_case_insensitive);
|
||||||
} else if (streq(key, "SYSCTL")) {
|
} else if (streq(key, "SYSCTL")) {
|
||||||
r = check_attr_format_and_warn(rule_line, key, attr);
|
r = check_attr_format_and_warn(rule_line, key, attr);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -766,30 +778,30 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
|
|
||||||
if (!is_match) {
|
if (!is_match) {
|
||||||
check_value_format_and_warn(rule_line, key, value, false);
|
check_value_format_and_warn(rule_line, key, value, false);
|
||||||
r = rule_line_add_token(rule_line, TK_A_SYSCTL, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_A_SYSCTL, op, value, attr, /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_SYSCTL, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_M_SYSCTL, op, value, attr, is_case_insensitive);
|
||||||
} else if (streq(key, "KERNELS")) {
|
} else if (streq(key, "KERNELS")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_KERNEL, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_KERNEL, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "SUBSYSTEMS")) {
|
} else if (streq(key, "SUBSYSTEMS")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_SUBSYSTEM, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_SUBSYSTEM, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "DRIVERS")) {
|
} else if (streq(key, "DRIVERS")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_DRIVER, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_DRIVER, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "ATTRS")) {
|
} else if (streq(key, "ATTRS")) {
|
||||||
r = check_attr_format_and_warn(rule_line, key, attr);
|
r = check_attr_format_and_warn(rule_line, key, attr);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -802,14 +814,14 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (strstr(attr, "../"))
|
if (strstr(attr, "../"))
|
||||||
log_line_warning(rule_line, "Direct reference to parent sysfs directory, may break in future kernels.");
|
log_line_warning(rule_line, "Direct reference to parent sysfs directory, may break in future kernels.");
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_ATTR, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_ATTR, op, value, attr, is_case_insensitive);
|
||||||
} else if (streq(key, "TAGS")) {
|
} else if (streq(key, "TAGS")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_TAG, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_TAG, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "TEST")) {
|
} else if (streq(key, "TEST")) {
|
||||||
mode_t mode = MODE_INVALID;
|
mode_t mode = MODE_INVALID;
|
||||||
|
|
||||||
|
@ -821,8 +833,10 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
check_value_format_and_warn(rule_line, key, value, true);
|
check_value_format_and_warn(rule_line, key, value, true);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
if (is_case_insensitive)
|
||||||
|
return log_line_invalid_prefix(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_TEST, op, value, MODE_TO_PTR(mode));
|
r = rule_line_add_token(rule_line, TK_M_TEST, op, value, MODE_TO_PTR(mode), is_case_insensitive);
|
||||||
} else if (streq(key, "PROGRAM")) {
|
} else if (streq(key, "PROGRAM")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
|
@ -831,8 +845,10 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
op = OP_MATCH;
|
op = OP_MATCH;
|
||||||
|
if (is_case_insensitive)
|
||||||
|
return log_line_invalid_prefix(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_PROGRAM, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_PROGRAM, op, value, NULL, /* is_case_insensitive */ false);
|
||||||
} else if (streq(key, "IMPORT")) {
|
} else if (streq(key, "IMPORT")) {
|
||||||
if (isempty(attr))
|
if (isempty(attr))
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
|
@ -841,18 +857,20 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
op = OP_MATCH;
|
op = OP_MATCH;
|
||||||
|
if (is_case_insensitive)
|
||||||
|
return log_line_invalid_prefix(rule_line, key);
|
||||||
|
|
||||||
if (streq(attr, "file"))
|
if (streq(attr, "file"))
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_FILE, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_FILE, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(attr, "program")) {
|
else if (streq(attr, "program")) {
|
||||||
UdevBuiltinCommand cmd;
|
UdevBuiltinCommand cmd;
|
||||||
|
|
||||||
cmd = udev_builtin_lookup(value);
|
cmd = udev_builtin_lookup(value);
|
||||||
if (cmd >= 0) {
|
if (cmd >= 0) {
|
||||||
log_line_debug(rule_line, "Found builtin command '%s' for %s, replacing attribute.", value, key);
|
log_line_debug(rule_line, "Found builtin command '%s' for %s, replacing attribute.", value, key);
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd));
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd), /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_PROGRAM, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_PROGRAM, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
} else if (streq(attr, "builtin")) {
|
} else if (streq(attr, "builtin")) {
|
||||||
UdevBuiltinCommand cmd;
|
UdevBuiltinCommand cmd;
|
||||||
|
|
||||||
|
@ -860,13 +878,13 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (cmd < 0)
|
if (cmd < 0)
|
||||||
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Unknown builtin command: %s", value);
|
"Unknown builtin command: %s", value);
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd));
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd), /* is_case_insensitive = */ false);
|
||||||
} else if (streq(attr, "db"))
|
} else if (streq(attr, "db"))
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_DB, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_DB, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(attr, "cmdline"))
|
else if (streq(attr, "cmdline"))
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_CMDLINE, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_CMDLINE, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(attr, "parent"))
|
else if (streq(attr, "parent"))
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_PARENT, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_PARENT, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
else
|
else
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
} else if (streq(key, "RESULT")) {
|
} else if (streq(key, "RESULT")) {
|
||||||
|
@ -875,7 +893,7 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_RESULT, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_RESULT, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "OPTIONS")) {
|
} else if (streq(key, "OPTIONS")) {
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
|
@ -887,24 +905,24 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
op = OP_ASSIGN;
|
op = OP_ASSIGN;
|
||||||
|
|
||||||
if (streq(value, "string_escape=none"))
|
if (streq(value, "string_escape=none"))
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_NONE, op, NULL, NULL);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_NONE, op, NULL, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(value, "string_escape=replace"))
|
else if (streq(value, "string_escape=replace"))
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_REPLACE, op, NULL, NULL);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_REPLACE, op, NULL, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(value, "db_persist"))
|
else if (streq(value, "db_persist"))
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DB_PERSIST, op, NULL, NULL);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DB_PERSIST, op, NULL, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(value, "watch"))
|
else if (streq(value, "watch"))
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(1));
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(1), /* is_case_insensitive = */ false);
|
||||||
else if (streq(value, "nowatch"))
|
else if (streq(value, "nowatch"))
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(0));
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(0), /* is_case_insensitive = */ false);
|
||||||
else if ((tmp = startswith(value, "static_node=")))
|
else if ((tmp = startswith(value, "static_node=")))
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STATIC_NODE, op, tmp, NULL);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STATIC_NODE, op, tmp, NULL, /* is_case_insensitive = */ false);
|
||||||
else if ((tmp = startswith(value, "link_priority="))) {
|
else if ((tmp = startswith(value, "link_priority="))) {
|
||||||
int prio;
|
int prio;
|
||||||
|
|
||||||
r = safe_atoi(tmp, &prio);
|
r = safe_atoi(tmp, &prio);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_line_error_errno(rule_line, r, "Failed to parse link priority '%s': %m", tmp);
|
return log_line_error_errno(rule_line, r, "Failed to parse link priority '%s': %m", tmp);
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DEVLINK_PRIORITY, op, NULL, INT_TO_PTR(prio));
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DEVLINK_PRIORITY, op, NULL, INT_TO_PTR(prio), /* is_case_insensitive = */ false);
|
||||||
} else if ((tmp = startswith(value, "log_level="))) {
|
} else if ((tmp = startswith(value, "log_level="))) {
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
|
@ -915,7 +933,7 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (level < 0)
|
if (level < 0)
|
||||||
return log_line_error_errno(rule_line, level, "Failed to parse log level '%s': %m", tmp);
|
return log_line_error_errno(rule_line, level, "Failed to parse log level '%s': %m", tmp);
|
||||||
}
|
}
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_LOG_LEVEL, op, NULL, INT_TO_PTR(level));
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_LOG_LEVEL, op, NULL, INT_TO_PTR(level), /* is_case_insensitive = */ false);
|
||||||
} else {
|
} else {
|
||||||
log_line_warning(rule_line, "Invalid value for OPTIONS key, ignoring: '%s'", value);
|
log_line_warning(rule_line, "Invalid value for OPTIONS key, ignoring: '%s'", value);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -933,17 +951,17 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_uid(value, &uid) >= 0)
|
if (parse_uid(value, &uid) >= 0)
|
||||||
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid));
|
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid), /* is_case_insensitive = */ false);
|
||||||
else if (resolve_name_timing == RESOLVE_NAME_EARLY &&
|
else if (resolve_name_timing == RESOLVE_NAME_EARLY &&
|
||||||
rule_get_substitution_type(value) == SUBST_TYPE_PLAIN) {
|
rule_get_substitution_type(value) == SUBST_TYPE_PLAIN) {
|
||||||
r = rule_resolve_user(rule_line, value, &uid);
|
r = rule_resolve_user(rule_line, value, &uid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_line_error_errno(rule_line, r, "Failed to resolve user name '%s': %m", value);
|
return log_line_error_errno(rule_line, r, "Failed to resolve user name '%s': %m", value);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid));
|
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid), /* is_case_insensitive = */ false);
|
||||||
} else if (resolve_name_timing != RESOLVE_NAME_NEVER) {
|
} else if (resolve_name_timing != RESOLVE_NAME_NEVER) {
|
||||||
check_value_format_and_warn(rule_line, key, value, true);
|
check_value_format_and_warn(rule_line, key, value, true);
|
||||||
r = rule_line_add_token(rule_line, TK_A_OWNER, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_OWNER, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
} else {
|
} else {
|
||||||
log_line_debug(rule_line, "User name resolution is disabled, ignoring %s=\"%s\".", key, value);
|
log_line_debug(rule_line, "User name resolution is disabled, ignoring %s=\"%s\".", key, value);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -961,17 +979,17 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_gid(value, &gid) >= 0)
|
if (parse_gid(value, &gid) >= 0)
|
||||||
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid));
|
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid), /* is_case_insensitive = */ false);
|
||||||
else if (resolve_name_timing == RESOLVE_NAME_EARLY &&
|
else if (resolve_name_timing == RESOLVE_NAME_EARLY &&
|
||||||
rule_get_substitution_type(value) == SUBST_TYPE_PLAIN) {
|
rule_get_substitution_type(value) == SUBST_TYPE_PLAIN) {
|
||||||
r = rule_resolve_group(rule_line, value, &gid);
|
r = rule_resolve_group(rule_line, value, &gid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_line_error_errno(rule_line, r, "Failed to resolve group name '%s': %m", value);
|
return log_line_error_errno(rule_line, r, "Failed to resolve group name '%s': %m", value);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid));
|
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid), /* is_case_insensitive = */ false);
|
||||||
} else if (resolve_name_timing != RESOLVE_NAME_NEVER) {
|
} else if (resolve_name_timing != RESOLVE_NAME_NEVER) {
|
||||||
check_value_format_and_warn(rule_line, key, value, true);
|
check_value_format_and_warn(rule_line, key, value, true);
|
||||||
r = rule_line_add_token(rule_line, TK_A_GROUP, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_GROUP, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
} else {
|
} else {
|
||||||
log_line_debug(rule_line, "Resolving group name is disabled, ignoring GROUP=\"%s\".", value);
|
log_line_debug(rule_line, "Resolving group name is disabled, ignoring GROUP=\"%s\".", value);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -989,10 +1007,10 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_mode(value, &mode) >= 0)
|
if (parse_mode(value, &mode) >= 0)
|
||||||
r = rule_line_add_token(rule_line, TK_A_MODE_ID, op, NULL, MODE_TO_PTR(mode));
|
r = rule_line_add_token(rule_line, TK_A_MODE_ID, op, NULL, MODE_TO_PTR(mode), /* is_case_insensitive = */ false);
|
||||||
else {
|
else {
|
||||||
check_value_format_and_warn(rule_line, key, value, true);
|
check_value_format_and_warn(rule_line, key, value, true);
|
||||||
r = rule_line_add_token(rule_line, TK_A_MODE, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_MODE, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
}
|
}
|
||||||
} else if (streq(key, "SECLABEL")) {
|
} else if (streq(key, "SECLABEL")) {
|
||||||
if (isempty(attr))
|
if (isempty(attr))
|
||||||
|
@ -1005,13 +1023,13 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
op = OP_ASSIGN;
|
op = OP_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_A_SECLABEL, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_A_SECLABEL, op, value, attr, /* is_case_insensitive = */ false);
|
||||||
} else if (streq(key, "RUN")) {
|
} else if (streq(key, "RUN")) {
|
||||||
if (is_match || op == OP_REMOVE)
|
if (is_match || op == OP_REMOVE)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
check_value_format_and_warn(rule_line, key, value, true);
|
check_value_format_and_warn(rule_line, key, value, true);
|
||||||
if (!attr || streq(attr, "program"))
|
if (!attr || streq(attr, "program"))
|
||||||
r = rule_line_add_token(rule_line, TK_A_RUN_PROGRAM, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_RUN_PROGRAM, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(attr, "builtin")) {
|
else if (streq(attr, "builtin")) {
|
||||||
UdevBuiltinCommand cmd;
|
UdevBuiltinCommand cmd;
|
||||||
|
|
||||||
|
@ -1019,7 +1037,7 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (cmd < 0)
|
if (cmd < 0)
|
||||||
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Unknown builtin command '%s', ignoring.", value);
|
"Unknown builtin command '%s', ignoring.", value);
|
||||||
r = rule_line_add_token(rule_line, TK_A_RUN_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd));
|
r = rule_line_add_token(rule_line, TK_A_RUN_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd), /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
} else if (streq(key, "GOTO")) {
|
} else if (streq(key, "GOTO")) {
|
||||||
|
@ -1119,13 +1137,30 @@ static void check_token_delimiters(UdevRuleLine *rule_line, const char *line) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {
|
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos, bool *ret_is_case_insensitive) {
|
||||||
char *i, *j;
|
char *i, *j;
|
||||||
bool is_escaped;
|
bool is_escaped = false, is_case_insensitive = false;
|
||||||
|
|
||||||
|
assert(str);
|
||||||
|
assert(ret_value);
|
||||||
|
assert(ret_endpos);
|
||||||
|
assert(ret_is_case_insensitive);
|
||||||
|
|
||||||
|
/* check if string is prefixed with:
|
||||||
|
* - "e" for escaped
|
||||||
|
* - "i" for case insensitive match
|
||||||
|
*
|
||||||
|
* Note both e and i can be set but do not allow duplicates ("eei", "eii"). */
|
||||||
|
for (const char *k = str; *k != '"' && k < str + 2; k++)
|
||||||
|
if (*k == 'e' && !is_escaped)
|
||||||
|
is_escaped = true;
|
||||||
|
else if (*k == 'i' && !is_case_insensitive)
|
||||||
|
is_case_insensitive = true;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
/* value must be double quotated */
|
/* value must be double quotated */
|
||||||
is_escaped = str[0] == 'e';
|
str += is_escaped + is_case_insensitive;
|
||||||
str += is_escaped;
|
|
||||||
if (str[0] != '"')
|
if (str[0] != '"')
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -1172,10 +1207,11 @@ int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {
|
||||||
|
|
||||||
*ret_value = str;
|
*ret_value = str;
|
||||||
*ret_endpos = i + 1;
|
*ret_endpos = i + 1;
|
||||||
|
*ret_is_case_insensitive = is_case_insensitive;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOperatorType *ret_op, char **ret_value) {
|
static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOperatorType *ret_op, char **ret_value, bool *ret_is_case_insensitive) {
|
||||||
char *key_begin, *key_end, *attr, *tmp;
|
char *key_begin, *key_end, *attr, *tmp;
|
||||||
UdevRuleOperatorType op;
|
UdevRuleOperatorType op;
|
||||||
int r;
|
int r;
|
||||||
|
@ -1185,6 +1221,7 @@ static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOper
|
||||||
assert(ret_key);
|
assert(ret_key);
|
||||||
assert(ret_op);
|
assert(ret_op);
|
||||||
assert(ret_value);
|
assert(ret_value);
|
||||||
|
assert(ret_is_case_insensitive);
|
||||||
|
|
||||||
key_begin = skip_leading_chars(*line, WHITESPACE ",");
|
key_begin = skip_leading_chars(*line, WHITESPACE ",");
|
||||||
|
|
||||||
|
@ -1219,7 +1256,7 @@ static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOper
|
||||||
|
|
||||||
tmp += op == OP_ASSIGN ? 1 : 2;
|
tmp += op == OP_ASSIGN ? 1 : 2;
|
||||||
tmp = skip_leading_chars(tmp, NULL);
|
tmp = skip_leading_chars(tmp, NULL);
|
||||||
r = udev_rule_parse_value(tmp, ret_value, line);
|
r = udev_rule_parse_value(tmp, ret_value, line, ret_is_case_insensitive);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1291,17 +1328,18 @@ static int rule_add_line(UdevRuleFile *rule_file, const char *line_str, unsigned
|
||||||
for (p = rule_line->line; !isempty(p); ) {
|
for (p = rule_line->line; !isempty(p); ) {
|
||||||
char *key, *attr, *value;
|
char *key, *attr, *value;
|
||||||
UdevRuleOperatorType op;
|
UdevRuleOperatorType op;
|
||||||
|
bool is_case_insensitive;
|
||||||
|
|
||||||
if (extra_checks)
|
if (extra_checks)
|
||||||
check_token_delimiters(rule_line, p);
|
check_token_delimiters(rule_line, p);
|
||||||
|
|
||||||
r = parse_line(&p, &key, &attr, &op, &value);
|
r = parse_line(&p, &key, &attr, &op, &value, &is_case_insensitive);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_line_error_errno(rule_line, r, "Invalid key/value pair, ignoring.");
|
return log_line_error_errno(rule_line, r, "Invalid key/value pair, ignoring.");
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
r = parse_token(rule_line, key, attr, op, value);
|
r = parse_token(rule_line, key, attr, op, value, is_case_insensitive);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -1412,7 +1450,6 @@ static bool tokens_eq(const UdevRuleToken *a, const UdevRuleToken *b) {
|
||||||
assert(b);
|
assert(b);
|
||||||
|
|
||||||
return a->attr_subst_type == b->attr_subst_type &&
|
return a->attr_subst_type == b->attr_subst_type &&
|
||||||
a->attr_match_remove_trailing_whitespace == b->attr_match_remove_trailing_whitespace &&
|
|
||||||
token_type_and_value_eq(a, b) &&
|
token_type_and_value_eq(a, b) &&
|
||||||
token_type_and_data_eq(a, b);
|
token_type_and_data_eq(a, b);
|
||||||
}
|
}
|
||||||
|
@ -1427,7 +1464,6 @@ static bool nulstr_tokens_conflict(const UdevRuleToken *a, const UdevRuleToken *
|
||||||
a->op == OP_MATCH &&
|
a->op == OP_MATCH &&
|
||||||
a->match_type == b->match_type &&
|
a->match_type == b->match_type &&
|
||||||
a->attr_subst_type == b->attr_subst_type &&
|
a->attr_subst_type == b->attr_subst_type &&
|
||||||
a->attr_match_remove_trailing_whitespace == b->attr_match_remove_trailing_whitespace &&
|
|
||||||
token_type_and_data_eq(a, b)))
|
token_type_and_data_eq(a, b)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1696,7 +1732,7 @@ bool udev_rules_should_reload(UdevRules *rules) {
|
||||||
|
|
||||||
static bool token_match_string(UdevRuleToken *token, const char *str) {
|
static bool token_match_string(UdevRuleToken *token, const char *str) {
|
||||||
const char *value;
|
const char *value;
|
||||||
bool match = false;
|
bool match = false, case_insensitive;
|
||||||
|
|
||||||
assert(token);
|
assert(token);
|
||||||
assert(token->value);
|
assert(token->value);
|
||||||
|
@ -1704,13 +1740,17 @@ static bool token_match_string(UdevRuleToken *token, const char *str) {
|
||||||
|
|
||||||
str = strempty(str);
|
str = strempty(str);
|
||||||
value = token->value;
|
value = token->value;
|
||||||
|
case_insensitive = FLAGS_SET(token->match_type, MATCH_CASE_INSENSITIVE);
|
||||||
|
|
||||||
switch (token->match_type) {
|
switch (token->match_type & _MATCH_TYPE_MASK) {
|
||||||
case MATCH_TYPE_EMPTY:
|
case MATCH_TYPE_EMPTY:
|
||||||
match = isempty(str);
|
match = isempty(str);
|
||||||
break;
|
break;
|
||||||
case MATCH_TYPE_SUBSYSTEM:
|
case MATCH_TYPE_SUBSYSTEM:
|
||||||
match = STR_IN_SET(str, "subsystem", "class", "bus");
|
if (case_insensitive)
|
||||||
|
match = STRCASE_IN_SET(str, "subsystem", "class", "bus");
|
||||||
|
else
|
||||||
|
match = STR_IN_SET(str, "subsystem", "class", "bus");
|
||||||
break;
|
break;
|
||||||
case MATCH_TYPE_PLAIN_WITH_EMPTY:
|
case MATCH_TYPE_PLAIN_WITH_EMPTY:
|
||||||
if (isempty(str)) {
|
if (isempty(str)) {
|
||||||
|
@ -1720,7 +1760,7 @@ static bool token_match_string(UdevRuleToken *token, const char *str) {
|
||||||
_fallthrough_;
|
_fallthrough_;
|
||||||
case MATCH_TYPE_PLAIN:
|
case MATCH_TYPE_PLAIN:
|
||||||
NULSTR_FOREACH(i, value)
|
NULSTR_FOREACH(i, value)
|
||||||
if (streq(i, str)) {
|
if (case_insensitive ? strcaseeq(i, str) : streq(i, str)) {
|
||||||
match = true;
|
match = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1733,7 +1773,7 @@ static bool token_match_string(UdevRuleToken *token, const char *str) {
|
||||||
_fallthrough_;
|
_fallthrough_;
|
||||||
case MATCH_TYPE_GLOB:
|
case MATCH_TYPE_GLOB:
|
||||||
NULSTR_FOREACH(i, value)
|
NULSTR_FOREACH(i, value)
|
||||||
if ((fnmatch(i, str, 0) == 0)) {
|
if ((fnmatch(i, str, case_insensitive ? FNM_CASEFOLD : 0) == 0)) {
|
||||||
match = true;
|
match = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1773,7 +1813,7 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* remove trailing whitespace, if not asked to match for it */
|
/* remove trailing whitespace, if not asked to match for it */
|
||||||
if (token->attr_match_remove_trailing_whitespace) {
|
if (FLAGS_SET(token->match_type, MATCH_REMOVE_TRAILING_WHITESPACE)) {
|
||||||
strscpy(vbuf, sizeof(vbuf), value);
|
strscpy(vbuf, sizeof(vbuf), value);
|
||||||
value = delete_trailing_chars(vbuf, NULL);
|
value = delete_trailing_chars(vbuf, NULL);
|
||||||
}
|
}
|
||||||
|
@ -1785,7 +1825,7 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* remove trailing whitespace, if not asked to match for it */
|
/* remove trailing whitespace, if not asked to match for it */
|
||||||
if (token->attr_match_remove_trailing_whitespace)
|
if (FLAGS_SET(token->match_type, MATCH_REMOVE_TRAILING_WHITESPACE))
|
||||||
delete_trailing_chars(vbuf, NULL);
|
delete_trailing_chars(vbuf, NULL);
|
||||||
|
|
||||||
return token_match_string(token, vbuf);
|
return token_match_string(token, vbuf);
|
||||||
|
|
|
@ -29,7 +29,7 @@ typedef enum ResolveNameTiming {
|
||||||
_RESOLVE_NAME_TIMING_INVALID = -EINVAL,
|
_RESOLVE_NAME_TIMING_INVALID = -EINVAL,
|
||||||
} ResolveNameTiming;
|
} ResolveNameTiming;
|
||||||
|
|
||||||
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos);
|
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos, bool *ret_is_case_insensitive);
|
||||||
int udev_rules_parse_file(UdevRules *rules, const char *filename, bool extra_checks, UdevRuleFile **ret);
|
int udev_rules_parse_file(UdevRules *rules, const char *filename, bool extra_checks, UdevRuleFile **ret);
|
||||||
unsigned udev_rule_file_get_issues(UdevRuleFile *rule_file);
|
unsigned udev_rule_file_get_issues(UdevRuleFile *rule_file);
|
||||||
UdevRules* udev_rules_new(ResolveNameTiming resolve_name_timing);
|
UdevRules* udev_rules_new(ResolveNameTiming resolve_name_timing);
|
||||||
|
|
|
@ -2313,6 +2313,17 @@ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c \"printf %%s 'foo1 foo2' | grep 'foo1 f
|
||||||
SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sd*", SYMLINK+="blockdev"
|
SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sd*", SYMLINK+="blockdev"
|
||||||
KERNEL=="sda6", OPTIONS+="link_priority=10"
|
KERNEL=="sda6", OPTIONS+="link_priority=10"
|
||||||
"""),
|
"""),
|
||||||
|
|
||||||
|
Rules.new(
|
||||||
|
"case insensitive match",
|
||||||
|
Device(
|
||||||
|
"/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
|
||||||
|
exp_links = ["ok"],
|
||||||
|
),
|
||||||
|
|
||||||
|
rules = r"""
|
||||||
|
KERNEL==i"SDA1", SUBSYSTEMS==i"SCSI", ATTRS{vendor}==i"a?a", SYMLINK+="ok"
|
||||||
|
"""),
|
||||||
]
|
]
|
||||||
|
|
||||||
def fork_and_run_udev(action: str, rules: Rules) -> None:
|
def fork_and_run_udev(action: str, rules: Rules) -> None:
|
||||||
|
|
|
@ -237,6 +237,8 @@ test_syntax_error 'ENV=="b"' 'Invalid attribute for ENV.'
|
||||||
test_syntax_error 'ENV{a}-="b"' 'Invalid operator for ENV.'
|
test_syntax_error 'ENV{a}-="b"' 'Invalid operator for ENV.'
|
||||||
test_syntax_error 'ENV{a}:="b"' "ENV key takes '==', '!=', '=', or '+=' operator, assuming '='."
|
test_syntax_error 'ENV{a}:="b"' "ENV key takes '==', '!=', '=', or '+=' operator, assuming '='."
|
||||||
test_syntax_error 'ENV{ACTION}="b"' "Invalid ENV attribute. 'ACTION' cannot be set."
|
test_syntax_error 'ENV{ACTION}="b"' "Invalid ENV attribute. 'ACTION' cannot be set."
|
||||||
|
test_syntax_error 'ENV{a}=i"b"' "Invalid prefix 'i' for 'ENV'. The 'i' prefix can be specified only for '==' or '!=' operator."
|
||||||
|
test_syntax_error 'ENV{a}+=i"b"' "Invalid prefix 'i' for 'ENV'. The 'i' prefix can be specified only for '==' or '!=' operator."
|
||||||
test_syntax_error 'CONST=="b"' 'Invalid attribute for CONST.'
|
test_syntax_error 'CONST=="b"' 'Invalid attribute for CONST.'
|
||||||
test_syntax_error 'CONST{a}=="b"' 'Invalid attribute for CONST.'
|
test_syntax_error 'CONST{a}=="b"' 'Invalid attribute for CONST.'
|
||||||
test_syntax_error 'CONST{arch}="b"' 'Invalid operator for CONST.'
|
test_syntax_error 'CONST{arch}="b"' 'Invalid operator for CONST.'
|
||||||
|
@ -275,10 +277,12 @@ test_syntax_error 'TEST{0644}="b"' 'Invalid operator for TEST.'
|
||||||
test_syntax_error 'PROGRAM{a}=="b"' 'Invalid attribute for PROGRAM.'
|
test_syntax_error 'PROGRAM{a}=="b"' 'Invalid attribute for PROGRAM.'
|
||||||
test_syntax_error 'PROGRAM-="b"' 'Invalid operator for PROGRAM.'
|
test_syntax_error 'PROGRAM-="b"' 'Invalid operator for PROGRAM.'
|
||||||
test_syntax_error 'PROGRAM=="%", NAME="b"' 'Invalid value "%" for PROGRAM (char 1: invalid substitution type), ignoring.'
|
test_syntax_error 'PROGRAM=="%", NAME="b"' 'Invalid value "%" for PROGRAM (char 1: invalid substitution type), ignoring.'
|
||||||
|
test_syntax_error 'PROGRAM==i"b"' "Invalid prefix 'i' for PROGRAM."
|
||||||
test_syntax_error 'IMPORT="b"' 'Invalid attribute for IMPORT.'
|
test_syntax_error 'IMPORT="b"' 'Invalid attribute for IMPORT.'
|
||||||
test_syntax_error 'IMPORT{a}="b"' 'Invalid attribute for IMPORT.'
|
test_syntax_error 'IMPORT{a}="b"' 'Invalid attribute for IMPORT.'
|
||||||
test_syntax_error 'IMPORT{a}-="b"' 'Invalid operator for IMPORT.'
|
test_syntax_error 'IMPORT{a}-="b"' 'Invalid operator for IMPORT.'
|
||||||
test_syntax_error 'IMPORT{file}=="%", NAME="b"' 'Invalid value "%" for IMPORT (char 1: invalid substitution type), ignoring.'
|
test_syntax_error 'IMPORT{file}=="%", NAME="b"' 'Invalid value "%" for IMPORT (char 1: invalid substitution type), ignoring.'
|
||||||
|
test_syntax_error 'IMPORT{file}==i"a", NAME="b"' "Invalid prefix 'i' for IMPORT."
|
||||||
test_syntax_error 'IMPORT{builtin}!="foo"' 'Unknown builtin command: foo'
|
test_syntax_error 'IMPORT{builtin}!="foo"' 'Unknown builtin command: foo'
|
||||||
test_syntax_error 'RESULT{a}=="b"' 'Invalid attribute for RESULT.'
|
test_syntax_error 'RESULT{a}=="b"' 'Invalid attribute for RESULT.'
|
||||||
test_syntax_error 'RESULT:="b"' 'Invalid operator for RESULT.'
|
test_syntax_error 'RESULT:="b"' 'Invalid operator for RESULT.'
|
||||||
|
|
|
@ -9,26 +9,39 @@ set -o pipefail
|
||||||
export SYSTEMD_LOG_LEVEL=debug
|
export SYSTEMD_LOG_LEVEL=debug
|
||||||
|
|
||||||
c='
|
c='
|
||||||
d /tmp/somedir
|
d$ /tmp/somedir
|
||||||
f /tmp/somedir/somefile - - - - baz
|
f$ /tmp/somedir/somefile - - - - baz
|
||||||
|
f /tmp/someotherfile - - - - qux
|
||||||
'
|
'
|
||||||
|
|
||||||
systemd-tmpfiles --create - <<<"$c"
|
systemd-tmpfiles --create - <<<"$c"
|
||||||
test -f /tmp/somedir/somefile
|
test -f /tmp/somedir/somefile
|
||||||
grep -q baz /tmp/somedir/somefile
|
grep -q baz /tmp/somedir/somefile
|
||||||
|
grep -q qux /tmp/someotherfile
|
||||||
|
|
||||||
systemd-tmpfiles --purge --dry-run - <<<"$c"
|
systemd-tmpfiles --purge --dry-run - <<<"$c"
|
||||||
test -f /tmp/somedir/somefile
|
test -f /tmp/somedir/somefile
|
||||||
grep -q baz /tmp/somedir/somefile
|
grep -q baz /tmp/somedir/somefile
|
||||||
|
grep -q qux /tmp/someotherfile
|
||||||
|
|
||||||
systemd-tmpfiles --purge - <<<"$c"
|
systemd-tmpfiles --purge - <<<"$c"
|
||||||
test ! -f /tmp/somedir/somefile
|
test ! -f /tmp/somedir/somefile
|
||||||
test ! -d /tmp/somedir/
|
test ! -d /tmp/somedir/
|
||||||
|
grep -q qux /tmp/someotherfile
|
||||||
|
|
||||||
systemd-tmpfiles --create --purge --dry-run - <<<"$c"
|
systemd-tmpfiles --create --purge --dry-run - <<<"$c"
|
||||||
test ! -f /tmp/somedir/somefile
|
test ! -f /tmp/somedir/somefile
|
||||||
test ! -d /tmp/somedir/
|
test ! -d /tmp/somedir/
|
||||||
|
grep -q qux /tmp/someotherfile
|
||||||
|
|
||||||
systemd-tmpfiles --create --purge - <<<"$c"
|
systemd-tmpfiles --create --purge - <<<"$c"
|
||||||
test -f /tmp/somedir/somefile
|
test -f /tmp/somedir/somefile
|
||||||
grep -q baz /tmp/somedir/somefile
|
grep -q baz /tmp/somedir/somefile
|
||||||
|
grep -q qux /tmp/someotherfile
|
||||||
|
|
||||||
|
systemd-tmpfiles --purge - <<<"$c"
|
||||||
|
test ! -f /tmp/somedir/somefile
|
||||||
|
test ! -d /tmp/somedir/
|
||||||
|
grep -q qux /tmp/someotherfile
|
||||||
|
|
||||||
|
rm /tmp/someotherfile
|
||||||
|
|
|
@ -8,5 +8,5 @@
|
||||||
# See tmpfiles.d(5) for details
|
# See tmpfiles.d(5) for details
|
||||||
|
|
||||||
{% if LINK_SHELL_EXTRA_DROPIN %}
|
{% if LINK_SHELL_EXTRA_DROPIN %}
|
||||||
L {{SHELLPROFILEDIR}}/70-systemd-shell-extra.sh - - - - {{LIBEXECDIR}}/profile.d/70-systemd-shell-extra.sh
|
L$ {{SHELLPROFILEDIR}}/70-systemd-shell-extra.sh - - - - {{LIBEXECDIR}}/profile.d/70-systemd-shell-extra.sh
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
# See tmpfiles.d(5) for details
|
# See tmpfiles.d(5) for details
|
||||||
|
|
||||||
{% if LINK_SSH_PROXY_DROPIN %}
|
{% if LINK_SSH_PROXY_DROPIN %}
|
||||||
L {{SSHCONFDIR}}/20-systemd-ssh-proxy.conf - - - - {{LIBEXECDIR}}/ssh_config.d/20-systemd-ssh-proxy.conf
|
L$ {{SSHCONFDIR}}/20-systemd-ssh-proxy.conf - - - - {{LIBEXECDIR}}/ssh_config.d/20-systemd-ssh-proxy.conf
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if CREATE_SSHDPRIVSEPDIR %}
|
{% if CREATE_SSHDPRIVSEPDIR %}
|
||||||
d {{SSHDPRIVSEPDIR}} 0755
|
d {{SSHDPRIVSEPDIR}} 0755
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
d /run/lock 0755 root root -
|
d /run/lock 0755 root root -
|
||||||
L /var/lock - - - - ../run/lock
|
L /var/lock - - - - ../run/lock
|
||||||
{% if CREATE_LOG_DIRS %}
|
{% if CREATE_LOG_DIRS %}
|
||||||
L /var/log/README - - - - ../..{{DOC_DIR}}/README.logs
|
L$ /var/log/README - - - - ../..{{DOC_DIR}}/README.logs
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
# /run/lock/subsys is used for serializing SysV service execution, and
|
# /run/lock/subsys is used for serializing SysV service execution, and
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
# See tmpfiles.d(5) for details
|
# See tmpfiles.d(5) for details
|
||||||
|
|
||||||
d /run/systemd/netif 0755 systemd-network systemd-network -
|
d$ /run/systemd/netif 0755 systemd-network systemd-network -
|
||||||
d /run/systemd/netif/links 0755 systemd-network systemd-network -
|
d$ /run/systemd/netif/links 0755 systemd-network systemd-network -
|
||||||
d /run/systemd/netif/leases 0755 systemd-network systemd-network -
|
d$ /run/systemd/netif/leases 0755 systemd-network systemd-network -
|
||||||
d /var/lib/systemd/network 0755 systemd-network systemd-network -
|
d$ /var/lib/systemd/network 0755 systemd-network systemd-network -
|
||||||
|
|
|
@ -19,5 +19,5 @@ Q /var/lib/machines 0700 - - -
|
||||||
# systemd-nspawn --ephemeral places snapshots) we are more strict, to
|
# systemd-nspawn --ephemeral places snapshots) we are more strict, to
|
||||||
# avoid removing unrelated temporary files.
|
# avoid removing unrelated temporary files.
|
||||||
|
|
||||||
R! /var/lib/machines/.#*
|
R!$ /var/lib/machines/.#*
|
||||||
R! /.#machine.*
|
R!$ /.#machine.*
|
||||||
|
|
|
@ -14,10 +14,10 @@ x /var/tmp/systemd-private-%b-*
|
||||||
X /var/tmp/systemd-private-%b-*/tmp
|
X /var/tmp/systemd-private-%b-*/tmp
|
||||||
|
|
||||||
# Remove top-level private temporary directories on each boot
|
# Remove top-level private temporary directories on each boot
|
||||||
R! /tmp/systemd-private-*
|
R!$ /tmp/systemd-private-*
|
||||||
R! /var/tmp/systemd-private-*
|
R!$ /var/tmp/systemd-private-*
|
||||||
|
|
||||||
# Handle lost systemd-coredump temp files. They could be lost on old filesystems,
|
# Handle lost systemd-coredump temp files. They could be lost on old filesystems,
|
||||||
# for example, after hard reboot.
|
# for example, after hard reboot.
|
||||||
x /var/lib/systemd/coredump/.#core*.%b*
|
x /var/lib/systemd/coredump/.#core*.%b*
|
||||||
r! /var/lib/systemd/coredump/.#*
|
r!$ /var/lib/systemd/coredump/.#*
|
||||||
|
|
|
@ -13,11 +13,11 @@ f+! /run/utmp 0664 root utmp -
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
d /run/systemd/ask-password 0755 root root -
|
d /run/systemd/ask-password 0755 root root -
|
||||||
d /run/systemd/seats 0755 root root -
|
d$ /run/systemd/seats 0755 root root -
|
||||||
d /run/systemd/sessions 0755 root root -
|
d$ /run/systemd/sessions 0755 root root -
|
||||||
d /run/systemd/users 0755 root root -
|
d$ /run/systemd/users 0755 root root -
|
||||||
d /run/systemd/machines 0755 root root -
|
d /run/systemd/machines 0755 root root -
|
||||||
d /run/systemd/shutdown 0755 root root -
|
d$ /run/systemd/shutdown 0755 root root -
|
||||||
|
|
||||||
d /run/log 0755 root root -
|
d /run/log 0755 root root -
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue