1
0
mirror of https://github.com/systemd/systemd synced 2025-11-08 19:34:45 +01:00

Compare commits

...

39 Commits

Author SHA1 Message Date
Lennart Poettering
d08a6ec39c update TODO 2020-05-19 19:58:26 +02:00
Zbigniew Jędrzejewski-Szmek
1c3232e4a4
Merge pull request #15482 from ssahani/dhcpv6-userclass
network: DHCPv6 Introduce  user class
2020-05-19 19:38:06 +02:00
Michal Koutný
38fee61952 systemctl: Fix frozen state coloring
When unit is in an unhighlighted state, freezer coloring won't be turned off
(active_off is empty) until the end of the TTY output.
2020-05-19 19:35:36 +02:00
Lennart Poettering
d31dda5e95
Merge pull request #15637 from poettering/cryptsetup-literal
a number of cryptsetup fixes and additions
2020-05-19 19:28:42 +02:00
Lennart Poettering
6e41f4dd91 man: document the newly acquired cryptsetup features 2020-05-19 17:28:47 +02:00
Lennart Poettering
4eb08bdb71 cryptsetup: fix minor indentation issue 2020-05-19 17:28:43 +02:00
Lennart Poettering
0ba6f85ed3 cryptsetup: optionally, see if empty password works for unlocking the file system
This adds a new switch try-empty-password. If set and none of PKCS#11 or
key files work, it is attempted to unlock the volume with an empty
password, before the user is asked for a password.

Usecase: an installer generates an OS image on one system, which is the
booted up for the first time in a possibly different system. The image
is encrypted using a random volume key, but an empty password. A tool
that runs on first boot then queries the user for a password to set or
enrols the volume in the TPM, removing the empty password. (Of course, in
such a scenario it is important to never reuse the installer image on
multiple systems as they all will have the same volume key, but that's a
different question.)
2020-05-19 17:28:40 +02:00
Lennart Poettering
2424fb7e7b cryptsetup: fix minor memory leak 2020-05-19 17:28:36 +02:00
Lennart Poettering
c6b1d7d1da cryptsetup: also check for /dev/hwrng as random device node 2020-05-19 17:28:33 +02:00
Lennart Poettering
cb6c9283b5 cryptsetup: make sure to return EAGAIN on wrong tcrypt password too
Only then we'll try again to ask the user for a password.

Fixes: #12152
2020-05-19 17:28:29 +02:00
Lennart Poettering
7407f68980 cryptsetup: automatically load luks keys off disk
Let's make loading of keys a bit more automatic and define a common
place where key files can be placed. Specifically, whenever a volume of
name "foo" is attempted, search for a key file in
/etc/cryptsetup-keys.d/foo.key and /run/cryptsetup-keys.d/foo.key,
unless a key file is declared explicitly.

With this scheme we have a simple discovery in place that should make it
more straightfoward wher to place keys, and requires no explicit
configuration to be used.
2020-05-19 17:28:25 +02:00
Lennart Poettering
23769fb371 cryptsetup: split out key loading from pkcs11 code and teach search path logic
Let's do some rearrangements, so that we can later on use this to
automatically search for a key file.
2020-05-19 17:28:16 +02:00
Lennart Poettering
d3d49e7649 cryptsetup: optionally remove key file after use
This is useful when the key file is acquired dynamically in some form
and should be erased after use.

Note that this code tries to be robust, and removes the key file both on
success and on failure.
2020-05-19 17:28:13 +02:00
Lennart Poettering
8ced40c09b cryptsetup: catch up with debian crypttab options a bit
Support some aliases Debian added, and drop some options that Debian
dropped from our list of unsupported options.
2020-05-19 17:28:09 +02:00
Lennart Poettering
053e0626db fs-util: teach unlinkat_deallocate() a simple scheme for overwriting for erasing
With that it becomes useful for deleting password files and such.
2020-05-19 17:27:13 +02:00
Lennart Poettering
1d06deba0f
Merge pull request #15845 from poettering/btrfs-encrypted-fix
make path_is_encrypted() test pass on btrfs inside container
2020-05-19 17:15:22 +02:00
Zbigniew Jędrzejewski-Szmek
2946d46355
Merge pull request #15843 from poettering/busctl-duplicate-tweaks
busctl: improve log messages on duplicate members or interfaces
2020-05-19 16:33:46 +02:00
Lennart Poettering
f12465466d
Merge pull request #15848 from keszybz/small-doc-tweaks
A few tweaks to docs
2020-05-19 16:29:58 +02:00
Zbigniew Jędrzejewski-Szmek
70fcda8562 NEWS: retroactively document Family=
Requested in https://github.com/systemd/systemd/issues/13233#issuecomment-630800112.
2020-05-19 16:21:52 +02:00
Lennart Poettering
544e146b0e journalctl,elsewhere: make sure --file=foo fails with sane error msg if foo is not readable
It annoyed me for quite a while that running "journalctl --file=…" on a
file that is not readable failed with a "File not found" error instead
of a permission error. Let's fix that.

We make this work by using the GLOB_NOCHECK flag for glob() which means
that files are not accessible will be returned in the array as they are
instead of being filtered away. This then means that our later attemps
to open the files will fail cleanly with a good error message.
2020-05-19 15:26:51 +02:00
Zbigniew Jędrzejewski-Szmek
7f6b827f36
Merge pull request #15836 from poettering/makefs-lock
lock whole block device file running makefs
2020-05-19 15:23:23 +02:00
Lennart Poettering
feb13fca97 repart: don't insist on coming up on partition label ourselves
If the user specified a label, use that.

Fixes: #15841
2020-05-19 15:04:01 +02:00
Lennart Poettering
3468e5ac51 btrfs-util: tweak error code a bit 2020-05-19 12:12:00 +02:00
Lennart Poettering
f8838c6c2f test-fs-util: don't fail on btrfs file systems in containers
Fixes: #15821
2020-05-19 12:11:12 +02:00
Susant Sahani
ffed0205c7 DHCP: Use UINT8_MAX instead of 255 2020-05-19 11:48:37 +02:00
Susant Sahani
f37f2a6b8a network: DHCPv6 - Add support to send user class
Frame 115: 171 bytes on wire (1368 bits), 171 bytes captured (1368 bits) on interface veth-peer, id 0
Ethernet II, Src: 1e:04:f8:b8:2f:d4 (1e:04:f8:b8:2f:d4), Dst: IPv6mcast_01:00:02 (33:33:00:01:00:02)
Internet Protocol Version 6, Src: fe80::1c04:f8ff:feb8:2fd4, Dst: ff02::1:2
User Datagram Protocol, Src Port: 546, Dst Port: 547
DHCPv6
    Message type: Solicit (1)
    Transaction ID: 0x673257
    Rapid Commit
        Option: Rapid Commit (14)
        Length: 0
    Identity Association for Non-temporary Address
        Option: Identity Association for Non-temporary Address (3)
        Length: 12
        Value: d0cc94090000000000000000
        IAID: d0cc9409
        T1: 0
        T2: 0
    Fully Qualified Domain Name
        Option: Fully Qualified Domain Name (39)
        Length: 6
        Value: 01045a657573
        0000 0... = Reserved: 0x00
        .... .0.. = N bit: Server should perform DNS updates
        .... ..0. = O bit: Server has not overridden client's S bit preference
        .... ...1 = S bit: Server should perform forward DNS updates
        Client FQDN: Zeus
    User Class
        Option: User Class (15)
        Length: 17
        Value: 000f68656c6c6f30313233343031323334
    Identity Association for Prefix Delegation
        Option: Identity Association for Prefix Delegation (25)
        Length: 12
        Value: d0cc94090000000000000000
        IAID: d0cc9409
        T1: 0
        T2: 0
    Option Request
        Option: Option Request (6)
        Length: 10
        Value: 001700180038001f000e
        Requested Option code: DNS recursive name server (23)
        Requested Option code: Domain Search List (24)
        Requested Option code: NTP Server (56)
        Requested Option code: Simple Network Time Protocol Server (31)
        Requested Option code: Rapid Commit (14)
    Client Identifier
        Option: Client Identifier (1)
        Length: 14
        Value: 00020000ab11d258482fc7eee651
        DUID: 00020000ab11d258482fc7eee651
        DUID Type: assigned by vendor based on Enterprise number (2)
        Enterprise ID: Tom Gundersen (systemd) (43793)
        Identifier: d258482fc7eee651
    Elapsed time
        Option: Elapsed time (8)
        Length: 2
        Value: 0bd0
        Elapsed time: 30240ms
2020-05-19 11:48:30 +02:00
Susant Sahani
3392392518 sd-network: DHCPv6 - add support to send userclass option
sd-network: DHCPv6 - add support to send userclass option

21.15.  User Class Option

   The User Class option is used by a client to identify the type or
   category of users or applications it represents.

   The format of the User Class option is:

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       OPTION_USER_CLASS       |          option-len           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      .                                                               .
      .                          user-class-data                      .
      .                                                               .
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                    Figure 26: User Class Option Format

      option-code          OPTION_USER_CLASS (15).

      option-len           Length of user-class-data field.

      user-class-data      The user classes carried by the client.  The
                           length, in octets, is specified by
                           option-len.

The information contained in the data area of this option is
   contained in one or more opaque fields that represent the user class
   or classes of which the client is a member.  A server selects
   configuration information for the client based on the classes
   identified in this option.  For example, the User Class option can be
   used to configure all clients of people in the accounting department
   with a different printer than clients of people in the marketing
   department.  The user class information carried in this option MUST
   be configurable on the client.

   The data area of the User Class option MUST contain one or more
   instances of user-class-data information.  Each instance of
   user-class-data is formatted as follows:

      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+
      |        user-class-len         |          opaque-data          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+

                Figure 27: Format of user-class-data Field
2020-05-19 11:44:51 +02:00
Lennart Poettering
f17153a721 busctl: improve error messages on duplicate members/interfaces
Prompted by: #15833
2020-05-19 09:11:15 +02:00
Lennart Poettering
9600c27c41 busctl: use structured initialization 2020-05-19 09:04:36 +02:00
Zbigniew Jędrzejewski-Szmek
11aaaa2c96 TODO: drop some external items
Those are either implemented or obsolete.
2020-05-19 08:59:53 +02:00
Zbigniew Jędrzejewski-Szmek
e2da649182 TODO: drop some networkd items
DUID/IAID — #2818, #2890, #3156,
Scope – #6449,
bond options — #10542,
option 119: sd_network_get_domains/sd_network_get_search_domains,
/proc/cmdline parsing – 426c1d385212e11cb,
wait states — #14536.
2020-05-19 08:56:53 +02:00
Zbigniew Jędrzejewski-Szmek
7b9289b1a0 man: fix dir name in sysctl.d(5)
Pointed out by Коренберг Марк in
e0f424790d (commitcomment-39259499).
2020-05-18 21:14:42 +02:00
Lennart Poettering
db2c56b0dd cryptsetup-generator: use systemd-makefs for implementation of "swap" and "tmp" options
This way we can take benefit of the correct block device locking we just
added.

I was thinking whether to instead pull in a regular
systemd-makefs@.service instance, but I couldn't come up with a reason
to, and thus opted for just doing the minimal patch and just replacing
the simply mkfs calls.

Fixes: #10179
Replaces: #13162
2020-05-18 20:50:03 +02:00
Lennart Poettering
a5a8fe2e8d makefs: normalize logging a bit 2020-05-18 20:50:03 +02:00
Lennart Poettering
0181ad85b3 makefs: lock device while we operate
Let's implement our own specs, i.e.

https://systemd.io/BLOCK_DEVICE_LOCKING/

This should address issues like this: #13162
2020-05-18 20:50:03 +02:00
Lennart Poettering
ac83e5aeca blockdev: add helper for locking whole block device 2020-05-18 18:41:56 +02:00
Lennart Poettering
58dfbfbdd6 dissect: use log_debug_errno() where appropriate 2020-05-18 18:41:56 +02:00
Lennart Poettering
700e0d3d87 makefs: log about OOM condition 2020-05-18 18:41:56 +02:00
Lennart Poettering
6cba41ab0d blockdev: propagate one more unexpected error 2020-05-18 18:41:56 +02:00
45 changed files with 726 additions and 262 deletions

3
NEWS
View File

@ -819,6 +819,9 @@ CHANGES WITH 243:
* systemd-networkd's TUN support gained a new setting VnetHeader= for
tweaking Generic Segment Offload support.
* The address family for policy rules may be specified using the new
Family= option in the [RoutingPolicyRule] section.
* networkctl gained a new "delete" command for removing virtual network
devices, as well as a new "--stats" switch for showing device
statistics.

21
TODO
View File

@ -22,6 +22,12 @@ Janitorial Clean-ups:
Features:
* machined: add API to acquire UID range. add API to mount/dissect loopback
file. Both protected by PK. Then make nspawn use these APIs to run
unprivileged containers. i.e. push the truly privileged bits into machined,
so that the client side can remain entirely unprivileged, with SUID or
anything like that.
* add "throttling" to sd-event event sources: optionally, when we wake up too
often for one, let's turn it off entirely for a while. Use that for the
/proc/self/mountinfo logic.
@ -1203,17 +1209,14 @@ Features:
* networkd:
- add more keys to [Route] and [Address] sections
- add support for more DHCPv4 options (and, longer term, other kinds of dynamic config)
- add proper initrd support (in particular generate .network/.link files based on /proc/cmdline)
- add reduced [Link] support to .network files
- add Scope= parsing option for [Network]
- properly handle routerless dhcp leases
- work with non-Ethernet devices
- add support for more bond options
- dhcp: do we allow configuring dhcp routes on interfaces that are not the one we got the dhcp info from?
- the DHCP lease data (such as NTP/DNS) is still made available when
a carrier is lost on a link. It should be removed instantly.
- expose in the API the following bits:
- option 15, domain name and/or option 119, search list
- option 15, domain name
- option 12, hostname and/or option 81, fqdn
- option 123, 144, geolocation
- option 252, configure http proxy (PAC/wpad)
@ -1222,12 +1225,8 @@ Features:
- allow Name= to be specified repeatedly in the [Match] section. Maybe also
support Name=foo*|bar*|baz ?
- duplicate address check for static IPs (like ARPCHECK in network-scripts)
- allow DUID/IAID to be customized, see issue #394.
- whenever uplink info changes, make DHCP server send out FORCERENEW
* networkd-wait-online:
- make operstates to wait for configurable?
* dhcp:
- figure out how much we can increase Maximum Message Size
@ -1251,20 +1250,14 @@ External:
- natively watch for dbus-*.service symlinks (PENDING)
- teach dbus to activate all services it finds in /etc/systemd/services/org-*.service
* fix alsa mixer restore to not print error when no config is stored
* make cryptsetup lower --iter-time
* patch kernel for xattr support in /dev, /proc/, /sys?
* kernel: add device_type = "fb", "fbcon" to class "graphics"
* /usr/bin/service should actually show the new command line
* fedora: suggest auto-restart on failure, but not on success and not on coredump. also, ask people to think about changing the start limit logic. Also point people to RestartPreventExitStatus=, SuccessExitStatus=
* fedora: F20: go timer units all the way, leave cron.daily for cron
* neither pkexec nor sudo initialize environ[] from the PAM environment?
* fedora: update policy to declare access mode and ownership of unit files to root:root 0644, and add an rpmlint check for it

View File

@ -41,7 +41,7 @@
character are ignored. Each of the remaining lines describes one
encrypted block device. Fields are delimited by white space.</para>
<para>Each line is in the form<programlisting><replaceable>name</replaceable> <replaceable>encrypted-device</replaceable> <replaceable>password</replaceable> <replaceable>options</replaceable></programlisting>
<para>Each line is in the form<programlisting><replaceable>volume-name</replaceable> <replaceable>encrypted-device</replaceable> <replaceable>key-file</replaceable> <replaceable>options</replaceable></programlisting>
The first two fields are mandatory, the remaining two are
optional.</para>
@ -53,24 +53,20 @@
it is opened as a LUKS device; otherwise, it is assumed to be in
raw dm-crypt (plain mode) format.</para>
<para>The first field contains the name of the resulting encrypted
block device; the device is set up within
<filename>/dev/mapper/</filename>.</para>
<para>The first field contains the name of the resulting encrypted volume; its block device is set up
below <filename>/dev/mapper/</filename>.</para>
<para>The second field contains a path to the underlying block
device or file, or a specification of a block device via
<literal>UUID=</literal> followed by the UUID.</para>
<para>The third field specifies the encryption password. If the
field is not present or the password is set to
<literal>none</literal> or <literal>-</literal>, the password has
to be manually entered during system boot. Otherwise, the field is
interpreted as an absolute path to a file containing the encryption
password. For swap encryption, <filename>/dev/urandom</filename>
or the hardware device <filename>/dev/hw_random</filename> can be
used as the password file; using <filename>/dev/random</filename>
may prevent boot completion if the system does not have enough
entropy to generate a truly random encryption key.</para>
<para>The third field specifies an absolute path to a file to read the encryption key from. If the field
is not present or set to <literal>none</literal> or <literal>-</literal>, a key file named after the
volume to unlock (i.e. the first column of the line), suffixed with <filename>.key</filename> is
automatically loaded from the <filename>/etc/cryptsetup-keys.d/</filename> and
<filename>/run/cryptsetup-keys.d/</filename> directories, if present. Otherwise, the password has to be
manually entered during system boot. For swap encryption, <filename>/dev/urandom</filename> may be used
as key file.</para>
<para>The fourth field, if present, is a comma-delimited list of
options. The following options are recognized:</para>
@ -138,6 +134,15 @@
size is then given by the key size.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>keyfile-erase</option></term>
<listitem><para>If enabled, the specified key file is erased after the volume is activated or when
activation fails. This is in particular useful when the key file is only acquired transiently before
activation (e.g. via a file in <filename>/run/</filename>, generated by a service running before
activation), and shall be removed after use. Defaults to off.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>key-slot=</option></term>
@ -431,6 +436,15 @@
before it is used to unlock the LUKS volume.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>try-empty-password=</option></term>
<listitem><para>Takes a boolean argument. If enabled, right before asking the user for a password it
is first attempted to unlock the volume with an empty password. This is useful for systems that are
initialized with an encrypted volume with only an empty password set, which shall be replaced with a
suitable password during first boot, but after activation.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>x-systemd.device-timeout=</option></term>

View File

@ -159,7 +159,7 @@ net.bridge.bridge-nf-call-arptables = 0
<example>
<title>Set network routing properties for all interfaces</title>
<para><filename>/etc/systemd/20-rp_filter.conf</filename>:</para>
<para><filename>/etc/sysctl.d/20-rp_filter.conf</filename>:</para>
<programlisting>net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.*.rp_filter = 2

View File

@ -44,6 +44,32 @@
<para>At early boot and when the system manager configuration is reloaded, <filename>/etc/crypttab</filename> is
translated into <filename>systemd-cryptsetup@.service</filename> units by
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
<para>In order to unlock a volume a password or binary key is
required. <filename>systemd-cryptsetup@.service</filename> tries to acquire a suitable password or binary
key via the following mechanisms, tried in order:</para>
<orderedlist>
<listitem><para>If a key file is explicitly configured (via the third column in
<filename>/etc/crypttab</filename>), a key read from it is used. If a PKCS#11 token is configured
(using the <varname>pkcs11-uri=</varname> option) the key is decrypted before use.</para></listitem>
<listitem><para>If no key file is configured explicitly this way, a key file is automatically loaded
from <filename>/etc/cryptsetup-keys.d/<replaceable>volume</replaceable>.key</filename> and
<filename>/run/cryptsetup-keys.d/<replaceable>volume</replaceable>.key</filename>, if present. Here
too, if a PKCS#11 token is configured, any key found this way is decrypted before
use.</para></listitem>
<listitem><para>If the <varname>try-empty-password</varname> option is specified it is then attempted
to unlock the volume with an empty password.</para></listitem>
<listitem><para>The kernel keyring is then checked for a suitable cached password from previous
attempts.</para></listitem>
<listitem><para>Finally, the user is queried for a password, possibly multiple times.</para></listitem>
</orderedlist>
<para>If no suitable key may be acquired via any of the mechanisms describes above, volume activation fails.</para>
</refsect1>
<refsect1>

View File

@ -1774,6 +1774,20 @@
option numbers, the option number is an integer in the range 1..65536.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UserClass=</varname></term>
<listitem>
<para>A DHCPv6 client can use User Class option to identify the type or category of user or applications
it represents. The information contained in this option is a string that represents the user class of which
the client is a member. Each class sets an identifying string of information to be used by the DHCP
service to classify clients. Special characters in the data string may be escaped using
<ulink url="https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences">C-style
escapes</ulink>. This setting can be specified multiple times. If an empty string is specified,
then all options specified earlier are cleared. Takes a whitespace-separated list of strings. Note that
currently NUL bytes are not allowed.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -23,8 +23,9 @@ dd if=/dev/urandom of=plaintext.bin bs=128 count=1
base64 < plaintext.bin | tr -d '\n\r\t ' > plaintext.base64
# Encrypt this newly generated (binary) LUKS decryption key using the public key whose private key is on the
# Yubikey, store the result in /etc/encrypted-luks-key.bin, where we'll look for it during boot.
sudo openssl rsautl -encrypt -pubin -inkey pubkey.pem -in plaintext.bin -out /etc/encrypted-luks-key.bin
# Yubikey, store the result in /etc/cryptsetup-keys.d/mytest.key, where we'll look for it during boot.
mkdir -p /etc/cryptsetup-keys.d
sudo openssl rsautl -encrypt -pubin -inkey pubkey.pem -in plaintext.bin -out /etc/cryptsetup-keys.d/mytest.key
# Configure the LUKS decryption key on the LUKS device. We use very low pbkdf settings since the key already
# has quite a high quality (it comes directly from /dev/urandom after all), and thus we don't need to do much
@ -40,8 +41,10 @@ shred -u plaintext.bin plaintext.base64
rm pubkey.pem
# Test: Let's run systemd-cryptsetup to test if this all worked. The option string should contain the full
# PKCS#11 URI we have in the clipboard, it tells the tool how to decipher the encrypted LUKS key.
sudo systemd-cryptsetup attach mytest /dev/sdXn /etc/encrypted-luks-key.bin 'pkcs11-uri=pkcs11:…'
# PKCS#11 URI we have in the clipboard; it tells the tool how to decipher the encrypted LUKS key. Note that
# systemd-cryptsetup automatically searches for the encrypted key in /etc/cryptsetup-keys.d/, hence we do
# not need to specify the key file path explicitly here.
sudo systemd-cryptsetup attach mytest /dev/sdXn - 'pkcs11-uri=pkcs11:…'
# If that worked, let's now add the same line persistently to /etc/crypttab, for the future.
sudo bash -c 'echo "mytest /dev/sdXn /etc/encrypted-luks-key \'pkcs11-uri=pkcs11:…\'" >> /etc/crypttab'
sudo bash -c 'echo "mytest /dev/sdXn - \'pkcs11-uri=pkcs11:…\'" >> /etc/crypttab'

View File

@ -2227,8 +2227,10 @@ executable(
if conf.get('HAVE_LIBCRYPTSETUP') == 1
systemd_cryptsetup_sources = files('''
src/cryptsetup/cryptsetup.c
src/cryptsetup/cryptsetup-pkcs11.h
src/cryptsetup/cryptsetup-util.c
src/cryptsetup/cryptsetup-util.h
src/cryptsetup/cryptsetup.c
'''.split())
if conf.get('HAVE_P11KIT') == 1

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <sys/file.h>
#include <unistd.h>
#include "alloc-util.h"
@ -29,6 +30,8 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
*ret = d;
return 0;
}
if (errno != ENOENT)
return -errno;
/* If it is a partition find the originating device */
xsprintf_sys_block_path(p, "/partition", d);
@ -185,3 +188,29 @@ int get_block_device_harder(const char *path, dev_t *ret) {
return 1;
}
int lock_whole_block_device(dev_t devt, int operation) {
_cleanup_free_ char *whole_node = NULL;
_cleanup_close_ int lock_fd = -1;
dev_t whole_devt;
int r;
/* Let's get a BSD file lock on the whole block device, as per: https://systemd.io/BLOCK_DEVICE_LOCKING */
r = block_get_whole_disk(devt, &whole_devt);
if (r < 0)
return r;
r = device_path_make_major_minor(S_IFBLK, whole_devt, &whole_node);
if (r < 0)
return r;
lock_fd = open(whole_node, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (lock_fd < 0)
return -errno;
if (flock(lock_fd, operation) < 0)
return -errno;
return TAKE_FD(lock_fd);
}

View File

@ -18,3 +18,5 @@ int block_get_originating(dev_t d, dev_t *ret);
int get_block_device(const char *path, dev_t *dev);
int get_block_device_harder(const char *path, dev_t *dev);
int lock_whole_block_device(dev_t devt, int operation);

View File

@ -319,7 +319,7 @@ int btrfs_get_block_device_fd(int fd, dev_t *dev) {
return -errno;
if (!S_ISBLK(st.st_mode))
return -ENODEV;
return -ENOTBLK;
if (major(st.st_rdev) == 0)
return -ENODEV;

View File

@ -23,6 +23,7 @@
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "random-util.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h"
@ -1303,11 +1304,13 @@ void unlink_tempfilep(char (*p)[]) {
(void) unlink_noerrno(*p);
}
int unlinkat_deallocate(int fd, const char *name, int flags) {
int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
_cleanup_close_ int truncate_fd = -1;
struct stat st;
off_t l, bs;
assert((flags & ~(UNLINK_REMOVEDIR|UNLINK_ERASE)) == 0);
/* Operates like unlinkat() but also deallocates the file contents if it is a regular file and there's no other
* link to it. This is useful to ensure that other processes that might have the file open for reading won't be
* able to keep the data pinned on disk forever. This call is particular useful whenever we execute clean-up
@ -1324,7 +1327,7 @@ int unlinkat_deallocate(int fd, const char *name, int flags) {
* Note that we attempt deallocation, but failure to succeed with that is not considered fatal, as long as the
* primary job to delete the file is accomplished. */
if ((flags & AT_REMOVEDIR) == 0) {
if (!FLAGS_SET(flags, UNLINK_REMOVEDIR)) {
truncate_fd = openat(fd, name, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK);
if (truncate_fd < 0) {
@ -1340,7 +1343,7 @@ int unlinkat_deallocate(int fd, const char *name, int flags) {
}
}
if (unlinkat(fd, name, flags) < 0)
if (unlinkat(fd, name, FLAGS_SET(flags, UNLINK_REMOVEDIR) ? AT_REMOVEDIR : 0) < 0)
return -errno;
if (truncate_fd < 0) /* Don't have a file handle, can't do more ☹️ */
@ -1351,7 +1354,45 @@ int unlinkat_deallocate(int fd, const char *name, int flags) {
return 0;
}
if (!S_ISREG(st.st_mode) || st.st_blocks == 0 || st.st_nlink > 0)
if (!S_ISREG(st.st_mode))
return 0;
if (FLAGS_SET(flags, UNLINK_ERASE) && st.st_size > 0 && st.st_nlink == 0) {
uint64_t left = st.st_size;
char buffer[64 * 1024];
/* If erasing is requested, let's overwrite the file with random data once before deleting
* it. This isn't going to give you shred(1) semantics, but hopefully should be good enough
* for stuff backed by tmpfs at least.
*
* Note that we only erase like this if the link count of the file is zero. If it is higer it
* is still linked by someone else and we'll leave it to them to remove it securely
* eventually! */
random_bytes(buffer, sizeof(buffer));
while (left > 0) {
ssize_t n;
n = write(truncate_fd, buffer, MIN(sizeof(buffer), left));
if (n < 0) {
log_debug_errno(errno, "Failed to erase data in file '%s', ignoring.", name);
break;
}
assert(left >= (size_t) n);
left -= n;
}
/* Let's refresh metadata */
if (fstat(truncate_fd, &st) < 0) {
log_debug_errno(errno, "Failed to stat file '%s' for deallocation, ignoring: %m", name);
return 0;
}
}
/* Don't dallocate if there's nothing to deallocate or if the file is linked elsewhere */
if (st.st_blocks == 0 || st.st_nlink > 0)
return 0;
/* If this is a regular file, it actually took up space on disk and there are no other links it's time to

View File

@ -113,7 +113,13 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free);
int access_fd(int fd, int mode);
void unlink_tempfilep(char (*p)[]);
int unlinkat_deallocate(int fd, const char *name, int flags);
typedef enum UnlinkDeallocateFlags {
UNLINK_REMOVEDIR = 1 << 0,
UNLINK_ERASE = 1 << 1,
} UnlinkDeallocateFlags;
int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags);
int fsync_directory_of_file(int fd);
int fsync_full(int fd);

View File

@ -61,11 +61,11 @@ int glob_exists(const char *path) {
return true;
}
int glob_extend(char ***strv, const char *path) {
int glob_extend(char ***strv, const char *path, int flags) {
_cleanup_globfree_ glob_t g = {};
int k;
k = safe_glob(path, GLOB_NOSORT|GLOB_BRACE, &g);
k = safe_glob(path, GLOB_NOSORT|GLOB_BRACE|flags, &g);
if (k < 0)
return k;

View File

@ -11,7 +11,7 @@
int safe_glob(const char *path, int flags, glob_t *pglob);
int glob_exists(const char *path);
int glob_extend(char ***strv, const char *path);
int glob_extend(char ***strv, const char *path, int flags);
#define _cleanup_globfree_ _cleanup_(globfree)

View File

@ -1051,7 +1051,7 @@ int systemd_installation_has_version(const char *root, unsigned minimal_version)
if (!path)
return -ENOMEM;
r = glob_extend(&names, path);
r = glob_extend(&names, path, 0);
if (r == -ENOENT)
continue;
if (r < 0)

View File

@ -856,20 +856,24 @@ static int on_interface(const char *interface, uint64_t flags, void *userdata) {
assert(interface);
assert(members);
m = new0(Member, 1);
m = new(Member, 1);
if (!m)
return log_oom();
m->type = "interface";
m->flags = flags;
*m = (Member) {
.type = "interface",
.flags = flags,
};
r = free_and_strdup(&m->interface, interface);
if (r < 0)
return log_oom();
r = set_put(members, m);
if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate interface");
if (r == -EEXIST)
return log_error_errno(r, "Invalid introspection data: duplicate interface '%s'.", interface);
if (r < 0)
return log_oom();
m = NULL;
return 0;
@ -883,12 +887,14 @@ static int on_method(const char *interface, const char *name, const char *signat
assert(interface);
assert(name);
m = new0(Member, 1);
m = new(Member, 1);
if (!m)
return log_oom();
m->type = "method";
m->flags = flags;
*m = (Member) {
.type = "method",
.flags = flags,
};
r = free_and_strdup(&m->interface, interface);
if (r < 0)
@ -907,8 +913,10 @@ static int on_method(const char *interface, const char *name, const char *signat
return log_oom();
r = set_put(members, m);
if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate method");
if (r == -EEXIST)
return log_error_errno(r, "Invalid introspection data: duplicate method '%s' on interface '%s'.", name, interface);
if (r < 0)
return log_oom();
m = NULL;
return 0;
@ -922,12 +930,14 @@ static int on_signal(const char *interface, const char *name, const char *signat
assert(interface);
assert(name);
m = new0(Member, 1);
m = new(Member, 1);
if (!m)
return log_oom();
m->type = "signal";
m->flags = flags;
*m = (Member) {
.type = "signal",
.flags = flags,
};
r = free_and_strdup(&m->interface, interface);
if (r < 0)
@ -942,8 +952,10 @@ static int on_signal(const char *interface, const char *name, const char *signat
return log_oom();
r = set_put(members, m);
if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate signal");
if (r == -EEXIST)
return log_error_errno(r, "Invalid introspection data: duplicate signal '%s' on interface '%s'.", name, interface);
if (r < 0)
return log_oom();
m = NULL;
return 0;
@ -957,13 +969,15 @@ static int on_property(const char *interface, const char *name, const char *sign
assert(interface);
assert(name);
m = new0(Member, 1);
m = new(Member, 1);
if (!m)
return log_oom();
m->type = "property";
m->flags = flags;
m->writable = writable;
*m = (Member) {
.type = "property",
.flags = flags,
.writable = writable,
};
r = free_and_strdup(&m->interface, interface);
if (r < 0)
@ -978,8 +992,10 @@ static int on_property(const char *interface, const char *name, const char *sign
return log_oom();
r = set_put(members, m);
if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate property");
if (r == -EEXIST)
return log_error_errno(r, "Invalid introspection data: duplicate property '%s' on interface '%s'.", name, interface);
if (r < 0)
return log_oom();
m = NULL;
return 0;

View File

@ -237,7 +237,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_FILE:
r = glob_extend(&arg_file, optarg);
r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
if (r < 0)
return log_error_errno(r, "Failed to add paths: %m");
break;

View File

@ -188,7 +188,11 @@ static int print_dependencies(FILE *f, const char* device_path) {
/* None, nothing to do */
return 0;
if (PATH_IN_SET(device_path, "/dev/urandom", "/dev/random", "/dev/hw_random")) {
if (PATH_IN_SET(device_path,
"/dev/urandom",
"/dev/random",
"/dev/hw_random",
"/dev/hwrng")) {
/* RNG device, add random dep */
fputs("After=systemd-random-seed.service\n", f);
return 0;
@ -209,7 +213,9 @@ static int print_dependencies(FILE *f, const char* device_path) {
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
fprintf(f, "After=%1$s\nRequires=%1$s\n", unit);
fprintf(f,
"After=%1$s\n"
"Requires=%1$s\n", unit);
} else {
/* Regular file, add mount dependency */
_cleanup_free_ char *escaped_path = specifier_escape(device_path);
@ -367,12 +373,12 @@ static int create_disk(
if (tmp)
fprintf(f,
"ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
"ExecStartPost=" ROOTLIBEXECDIR "/systemd-makefs ext2 '/dev/mapper/%s'\n",
name_escaped);
if (swap)
fprintf(f,
"ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
"ExecStartPost=" ROOTLIBEXECDIR "/systemd-makefs swap '/dev/mapper/%s'\n",
name_escaped);
if (keydev)

View File

@ -10,6 +10,7 @@
#include "alloc-util.h"
#include "ask-password-api.h"
#include "cryptsetup-pkcs11.h"
#include "cryptsetup-util.h"
#include "escape.h"
#include "fd-util.h"
#include "format-util.h"
@ -19,73 +20,6 @@
#include "stat-util.h"
#include "strv.h"
#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
static int load_key_file(
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
void **ret_encrypted_key,
size_t *ret_encrypted_key_size) {
_cleanup_(erase_and_freep) char *buffer = NULL;
_cleanup_close_ int fd = -1;
ssize_t n;
int r;
assert(key_file);
assert(ret_encrypted_key);
assert(ret_encrypted_key_size);
fd = open(key_file, O_RDONLY|O_CLOEXEC);
if (fd < 0)
return log_error_errno(errno, "Failed to load encrypted PKCS#11 key: %m");
if (key_file_size == 0) {
struct stat st;
if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to stat key file: %m");
r = stat_verify_regular(&st);
if (r < 0)
return log_error_errno(r, "Key file is not a regular file: %m");
if (st.st_size == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
"Key file larger (%s) than allowed maximum size (%s), refusing.",
format_bytes(buf1, sizeof(buf1), st.st_size),
format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
}
if (key_file_offset >= (uint64_t) st.st_size)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
key_file_size = st.st_size - key_file_offset;
}
buffer = malloc(key_file_size);
if (!buffer)
return log_oom();
if (key_file_offset > 0)
n = pread(fd, buffer, key_file_size, key_file_offset);
else
n = read(fd, buffer, key_file_size);
if (n < 0)
return log_error_errno(errno, "Failed to read PKCS#11 key file: %m");
if (n == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");
*ret_encrypted_key = TAKE_PTR(buffer);
*ret_encrypted_key_size = (size_t) n;
return 0;
}
struct pkcs11_callback_data {
const char *friendly_name;
usec_t until;
@ -93,10 +27,13 @@ struct pkcs11_callback_data {
size_t encrypted_key_size;
void *decrypted_key;
size_t decrypted_key_size;
bool free_encrypted_key;
};
static void pkcs11_callback_data_release(struct pkcs11_callback_data *data) {
free(data->decrypted_key);
if (data->free_encrypted_key)
free(data->encrypted_key);
}
@ -160,9 +97,11 @@ static int pkcs11_callback(
int decrypt_pkcs11_key(
const char *friendly_name,
const char *pkcs11_uri,
const char *key_file,
const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
size_t key_file_size,
uint64_t key_file_offset,
const void *key_data, /* … or key_data and key_data_size (for literal keys) */
size_t key_data_size,
usec_t until,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size) {
@ -175,16 +114,25 @@ int decrypt_pkcs11_key(
assert(friendly_name);
assert(pkcs11_uri);
assert(key_file);
assert(key_file || key_data);
assert(ret_decrypted_key);
assert(ret_decrypted_key_size);
/* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
r = load_key_file(key_file, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
if (key_data) {
data.encrypted_key = (void*) key_data;
data.encrypted_key_size = key_data_size;
data.free_encrypted_key = false;
} else {
r = load_key_file(key_file, NULL, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
if (r < 0)
return r;
data.free_encrypted_key = true;
}
r = pkcs11_find_token(pkcs11_uri, pkcs11_callback, &data);
if (r < 0)
return r;

View File

@ -14,6 +14,8 @@ int decrypt_pkcs11_key(
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
const void *key_data,
size_t key_data_size,
usec_t until,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size);
@ -26,6 +28,8 @@ static inline int decrypt_pkcs11_key(
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
const void *key_data,
size_t key_data_size,
usec_t until,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size) {

View File

@ -0,0 +1,110 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <unistd.h>
#include "cryptsetup-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "memory-util.h"
#include "path-util.h"
#include "stat-util.h"
#include "strv.h"
#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
int load_key_file(
const char *key_file,
char **search_path,
size_t key_file_size,
uint64_t key_file_offset,
void **ret_key,
size_t *ret_key_size) {
_cleanup_(erase_and_freep) char *buffer = NULL;
_cleanup_free_ char *discovered_path = NULL;
_cleanup_close_ int fd = -1;
ssize_t n;
int r;
assert(key_file);
assert(ret_key);
assert(ret_key_size);
if (strv_isempty(search_path) || path_is_absolute(key_file)) {
fd = open(key_file, O_RDONLY|O_CLOEXEC);
if (fd < 0)
return log_error_errno(errno, "Failed to load key file '%s': %m", key_file);
} else {
char **i;
STRV_FOREACH(i, search_path) {
_cleanup_free_ char *joined;
joined = path_join(*i, key_file);
if (!joined)
return log_oom();
fd = open(joined, O_RDONLY|O_CLOEXEC);
if (fd >= 0) {
discovered_path = TAKE_PTR(joined);
break;
}
if (errno != ENOENT)
return log_error_errno(errno, "Failed to load key file '%s': %m", joined);
}
if (!discovered_path) {
/* Search path supplied, but file not found, report by returning NULL, but not failing */
*ret_key = NULL;
*ret_key_size = 0;
return 0;
}
assert(fd >= 0);
key_file = discovered_path;
}
if (key_file_size == 0) {
struct stat st;
if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to stat key file '%s': %m", key_file);
r = stat_verify_regular(&st);
if (r < 0)
return log_error_errno(r, "Key file is not a regular file: %m");
if (st.st_size == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
"Key file larger (%s) than allowed maximum size (%s), refusing.",
format_bytes(buf1, sizeof(buf1), st.st_size),
format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
}
if (key_file_offset >= (uint64_t) st.st_size)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
key_file_size = st.st_size - key_file_offset;
}
buffer = malloc(key_file_size);
if (!buffer)
return log_oom();
if (key_file_offset > 0)
n = pread(fd, buffer, key_file_size, key_file_offset);
else
n = read(fd, buffer, key_file_size);
if (n < 0)
return log_error_errno(errno, "Failed to read key file '%s': %m", key_file);
if (n == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");
*ret_key = TAKE_PTR(buffer);
*ret_key_size = (size_t) n;
return 1;
}

View File

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <inttypes.h>
#include <sys/types.h>
int load_key_file(
const char *key_file,
char **search_path,
size_t key_file_size,
uint64_t key_file_offset,
void **ret_key,
size_t *ret_key_size);

View File

@ -13,13 +13,16 @@
#include "ask-password-api.h"
#include "crypt-util.h"
#include "cryptsetup-pkcs11.h"
#include "cryptsetup-util.h"
#include "device-util.h"
#include "escape.h"
#include "fileio.h"
#include "fs-util.h"
#include "fstab-util.h"
#include "hexdecoct.h"
#include "log.h"
#include "main-func.h"
#include "memory-util.h"
#include "mount-util.h"
#include "nulstr-util.h"
#include "parse-util.h"
@ -42,6 +45,8 @@ static unsigned arg_sector_size = CRYPT_SECTOR_SIZE;
static int arg_key_slot = CRYPT_ANY_SLOT;
static unsigned arg_keyfile_size = 0;
static uint64_t arg_keyfile_offset = 0;
static bool arg_keyfile_erase = false;
static bool arg_try_empty_password = false;
static char *arg_hash = NULL;
static char *arg_header = NULL;
static unsigned arg_tries = 3;
@ -67,12 +72,14 @@ STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_uri, freep);
/* Options Debian's crypttab knows we don't:
precheck=
check=
checkargs=
noearly=
loud=
noearly
loud
quiet
keyscript=
tmp= (the version without argument is supported)
initramfs
*/
static int parse_one_option(const char *option) {
@ -126,7 +133,8 @@ static int parse_one_option(const char *option) {
return 0;
}
} else if ((val = startswith(option, "key-slot="))) {
} else if ((val = startswith(option, "key-slot=")) ||
(val = startswith(option, "keyslot="))) {
arg_type = ANY_LUKS;
r = safe_atoi(val, &arg_key_slot);
@ -160,7 +168,20 @@ static int parse_one_option(const char *option) {
return 0;
}
} else if ((val = startswith(option, "hash="))) {
} else if ((val = startswith(option, "keyfile-erase="))) {
r = parse_boolean(val);
if (r < 0) {
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
return 0;
}
arg_keyfile_erase = r;
} else if (streq(option, "keyfile-erase"))
arg_keyfile_erase = true;
else if ((val = startswith(option, "hash="))) {
r = free_and_strdup(&arg_hash, val);
if (r < 0)
return log_oom();
@ -202,13 +223,13 @@ static int parse_one_option(const char *option) {
arg_type = ANY_LUKS;
else if (streq(option, "tcrypt"))
arg_type = CRYPT_TCRYPT;
else if (streq(option, "tcrypt-hidden")) {
else if (STR_IN_SET(option, "tcrypt-hidden", "tcrypthidden")) {
arg_type = CRYPT_TCRYPT;
arg_tcrypt_hidden = true;
} else if (streq(option, "tcrypt-system")) {
arg_type = CRYPT_TCRYPT;
arg_tcrypt_system = true;
} else if (streq(option, "tcrypt-veracrypt")) {
} else if (STR_IN_SET(option, "tcrypt-veracrypt", "veracrypt")) {
arg_type = CRYPT_TCRYPT;
arg_tcrypt_veracrypt = true;
} else if (STR_IN_SET(option, "plain", "swap", "tmp"))
@ -242,7 +263,20 @@ static int parse_one_option(const char *option) {
if (r < 0)
return log_oom();
} else if (!streq(option, "x-initrd.attach"))
} else if ((val = startswith(option, "try-empty-password="))) {
r = parse_boolean(val);
if (r < 0) {
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
return 0;
}
arg_try_empty_password = r;
} else if (streq(option, "try-empty-password"))
arg_try_empty_password = true;
else if (!streq(option, "x-initrd.attach"))
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
return 0;
@ -440,6 +474,8 @@ static int attach_tcrypt(
struct crypt_device *cd,
const char *name,
const char *key_file,
const void *key_data,
size_t key_data_size,
char **passwords,
uint32_t flags) {
@ -453,7 +489,7 @@ static int attach_tcrypt(
assert(cd);
assert(name);
assert(key_file || (passwords && passwords[0]));
assert(key_file || key_data || !strv_isempty(passwords));
if (arg_pkcs11_uri)
/* Ask for a regular password */
@ -469,6 +505,10 @@ static int attach_tcrypt(
if (arg_tcrypt_veracrypt)
params.flags |= CRYPT_TCRYPT_VERA_MODES;
if (key_data) {
params.passphrase = key_data;
params.passphrase_size = key_data_size;
} else {
if (key_file) {
r = read_one_line_file(key_file, &passphrase);
if (r < 0) {
@ -479,12 +519,19 @@ static int attach_tcrypt(
params.passphrase = passphrase;
} else
params.passphrase = passwords[0];
params.passphrase_size = strlen(params.passphrase);
}
r = crypt_load(cd, CRYPT_TCRYPT, &params);
if (r < 0) {
if (key_file && r == -EPERM) {
if (r == -EPERM) {
if (key_data)
log_error_errno(r, "Failed to activate using discovered key. (Key not correct?)");
if (key_file)
log_error_errno(r, "Failed to activate using password file '%s'. (Key data not correct?)", key_file);
return -EAGAIN; /* log the actual error, but return EAGAIN */
}
@ -502,6 +549,8 @@ static int attach_luks_or_plain(
struct crypt_device *cd,
const char *name,
const char *key_file,
const void *key_data,
size_t key_data_size,
char **passwords,
uint32_t flags,
usec_t until) {
@ -571,7 +620,7 @@ static int attach_luks_or_plain(
_cleanup_free_ char *friendly = NULL;
size_t decrypted_key_size = 0;
if (!key_file)
if (!key_file && !key_data)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing.");
friendly = friendly_disk_name(crypt_get_device_name(cd), name);
@ -584,8 +633,8 @@ static int attach_luks_or_plain(
r = decrypt_pkcs11_key(
friendly,
arg_pkcs11_uri,
key_file,
arg_keyfile_size, arg_keyfile_offset,
key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data_size,
until,
&decrypted_key, &decrypted_key_size);
if (r >= 0)
@ -668,6 +717,18 @@ static int attach_luks_or_plain(
if (r < 0)
return log_error_errno(r, "Failed to activate with PKCS#11 acquired key: %m");
} else if (key_data) {
if (pass_volume_key)
r = crypt_activate_by_volume_key(cd, name, key_data, key_data_size, flags);
else
r = crypt_activate_by_passphrase(cd, name, arg_key_slot, key_data, key_data_size, flags);
if (r == -EPERM) {
log_error_errno(r, "Failed to activate. (Key incorrect?)");
return -EAGAIN; /* Log actual error, but return EAGAIN */
}
if (r < 0)
return log_error_errno(r, "Failed to activate: %m");
} else if (key_file) {
r = crypt_activate_by_keyfile_device_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
if (r == -EPERM) {
@ -748,6 +809,17 @@ static uint32_t determine_flags(void) {
return flags;
}
static void remove_and_erasep(const char **p) {
int r;
if (!*p)
return;
r = unlinkat_deallocate(AT_FDCWD, *p, UNLINK_ERASE);
if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Unable to erase key file '%s', ignoring: %m", *p);
}
static int run(int argc, char *argv[]) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r;
@ -774,13 +846,19 @@ static int run(int argc, char *argv[]) {
unsigned tries;
usec_t until;
crypt_status_info status;
_cleanup_(remove_and_erasep) const char *destroy_key_file = NULL;
const char *key_file = NULL;
_cleanup_(erase_and_freep) void *key_data = NULL;
size_t key_data_size = 0;
/* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
if (argc < 4)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach requires at least two arguments.");
if (!filename_is_valid(argv[2]))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", argv[2]);
if (argc >= 5 && !STR_IN_SET(argv[4], "", "-", "none")) {
if (path_is_absolute(argv[4]))
key_file = argv[4];
@ -797,6 +875,24 @@ static int run(int argc, char *argv[]) {
/* A delicious drop of snake oil */
(void) mlockall(MCL_FUTURE);
if (!key_file) {
const char *fn;
/* If a key file is not explicitly specified, search for a key in a well defined
* search path, and load it. */
fn = strjoina(argv[2], ".key");
r = load_key_file(fn,
STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"),
0, 0, /* Note we leave arg_keyfile_offset/arg_keyfile_size as something that only applies to arg_keyfile! */
&key_data, &key_data_size);
if (r < 0)
return r;
if (r > 0)
log_debug("Automatically discovered key for volume '%s'.", argv[2]);
} else if (arg_keyfile_erase)
destroy_key_file = key_file; /* let's get this baby erased when we leave */
if (arg_header) {
log_debug("LUKS header: %s", arg_header);
r = crypt_init(&cd, arg_header);
@ -843,7 +939,7 @@ static int run(int argc, char *argv[]) {
}
/* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
if (!key_file) {
if (!key_file && !key_data) {
r = crypt_activate_by_token(cd, argv[2], CRYPT_ANY_TOKEN, NULL, flags);
if (r >= 0) {
log_debug("Volume %s activated with LUKS token id %i.", argv[2], r);
@ -857,26 +953,53 @@ static int run(int argc, char *argv[]) {
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
_cleanup_strv_free_erase_ char **passwords = NULL;
if (!key_file && !arg_pkcs11_uri) {
/* When we were able to acquire multiple keys, let's always process them in this order:
*
* 1. A key acquired via PKCS#11 token
* 2. The discovered key: i.e. key_data + key_data_size
* 3. The configured key: i.e. key_file + arg_keyfile_offset + arg_keyfile_size
* 4. The empty password, in case arg_try_empty_password is set
* 5. We enquire the user for a password
*/
if (!key_file && !key_data && !arg_pkcs11_uri) {
if (arg_try_empty_password) {
/* Hmm, let's try an empty password now, but only once */
arg_try_empty_password = false;
key_data = strdup("");
if (!key_data)
return log_oom();
key_data_size = 0;
} else {
/* Ask the user for a passphrase only as last resort, if we have
* nothing else to check for */
r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
if (r == -EAGAIN)
continue;
if (r < 0)
return r;
}
}
if (streq_ptr(arg_type, CRYPT_TCRYPT))
r = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
r = attach_tcrypt(cd, argv[2], key_file, key_data, key_data_size, passwords, flags);
else
r = attach_luks_or_plain(cd, argv[2], key_file, passwords, flags, until);
r = attach_luks_or_plain(cd, argv[2], key_file, key_data, key_data_size, passwords, flags, until);
if (r >= 0)
break;
if (r != -EAGAIN)
return r;
/* Passphrase not correct? Let's try again! */
/* Key not correct? Let's try again! */
key_file = NULL;
arg_pkcs11_uri = NULL;
key_data = erase_and_free(key_data);
key_data_size = 0;
arg_pkcs11_uri = mfree(arg_pkcs11_uri);
}
if (arg_tries != 0 && tries >= arg_tries)
@ -884,6 +1007,9 @@ static int run(int argc, char *argv[]) {
} else if (streq(argv[1], "detach")) {
if (!filename_is_valid(argv[2]))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", argv[2]);
r = crypt_init_by_name(&cd, argv[2]);
if (r == -ENODEV) {
log_info("Volume %s already inactive.", argv[2]);

View File

@ -720,7 +720,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_FILE:
r = glob_extend(&arg_file, optarg);
r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
if (r < 0)
return log_error_errno(r, "Failed to add paths: %m");
break;

View File

@ -705,7 +705,7 @@ static int parse_argv(int argc, char *argv[]) {
* STDIN. To avoid confusion we hence don't document this feature. */
arg_file_stdin = true;
else {
r = glob_extend(&arg_file, optarg);
r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
if (r < 0)
return log_error_errno(r, "Failed to add paths: %m");
}

View File

@ -97,6 +97,7 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix);
int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class);
int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
size_t *optlen, uint8_t **optvalue);
int dhcp6_option_parse_status(DHCP6Option *option, size_t len);

View File

@ -167,6 +167,36 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
return r;
}
int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class) {
_cleanup_free_ uint8_t *p = NULL;
size_t total = 0, offset = 0;
char **s;
assert_return(buf && *buf && buflen && user_class, -EINVAL);
STRV_FOREACH(s, user_class) {
size_t len = strlen(*s);
uint8_t *q;
if (len > 0xffff)
return -ENAMETOOLONG;
q = realloc(p, total + len + 2);
if (!q)
return -ENOMEM;
p = q;
unaligned_write_be16(&p[offset], len);
memcpy(&p[offset + 2], *s, len);
offset += 2 + len;
total += 2 + len;
}
return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_USER_CLASS, total, p);
}
int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) {
DHCP6Option *option = (DHCP6Option *)buf;
size_t i = sizeof(*option) + sizeof(pd->ia_pd);

View File

@ -67,6 +67,7 @@ struct sd_dhcp6_client {
size_t req_opts_len;
char *fqdn;
char *mudurl;
char **user_class;
sd_event_source *receive_message;
usec_t retransmit_time;
uint8_t retransmit_count;
@ -385,6 +386,27 @@ int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mud
return free_and_strdup(&client->mudurl, mudurl);
}
int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_class) {
_cleanup_strv_free_ char **s = NULL;
char **p;
assert_return(client, -EINVAL);
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
assert_return(user_class, -EINVAL);
STRV_FOREACH(p, user_class)
if (strlen(*p) > UINT16_MAX)
return -ENAMETOOLONG;
s = strv_copy((char **) user_class);
if (!s)
return -ENOMEM;
client->user_class = TAKE_PTR(s);
return 0;
}
int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
assert_return(client, -EINVAL);
assert_return(delegation, -EINVAL);
@ -565,6 +587,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
return r;
}
if (client->user_class) {
r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
if (r < 0)
return r;
}
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix);
if (r < 0)
@ -611,6 +639,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
return r;
}
if (client->user_class) {
r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
if (r < 0)
return r;
}
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
if (r < 0)
@ -645,6 +679,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
return r;
}
if (client->user_class) {
r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
if (r < 0)
return r;
}
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
if (r < 0)
@ -1602,7 +1642,10 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
free(client->req_opts);
free(client->fqdn);
free(client->mudurl);
ordered_hashmap_free(client->extra_options);
strv_free(client->user_class);
return mfree(client);
}

View File

@ -267,7 +267,7 @@ int config_parse_dhcp6_pd_hint(
return 0;
}
int config_parse_dhcp6_mud_url(
int config_parse_dhcp_user_class(
const char *unit,
const char *filename,
unsigned line,
@ -279,6 +279,67 @@ int config_parse_dhcp6_mud_url(
void *data,
void *userdata) {
char ***l = data;
int r;
assert(l);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue)) {
*l = strv_free(*l);
return 0;
}
for (;;) {
_cleanup_free_ char *w = NULL;
r = extract_first_word(&rvalue, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to split user classes option, ignoring: %s", rvalue);
break;
}
if (r == 0)
break;
if (ltype == AF_INET) {
if (strlen(w) > UINT8_MAX) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"%s length is not in the range 1-255, ignoring.", w);
continue;
}
} else {
if (strlen(w) > UINT16_MAX) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"%s length is not in the range 1-65535, ignoring.", w);
continue;
}
}
r = strv_push(l, w);
if (r < 0)
return log_oom();
w = NULL;
}
return 0;
}
int config_parse_dhcp6_mud_url(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_free_ char *unescaped = NULL;
Network *network = data;
int r;
@ -299,7 +360,7 @@ int config_parse_dhcp6_mud_url(
return 0;
}
if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
if (!http_url_is_valid(unescaped) || strlen(unescaped) > UINT8_MAX) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"Failed to parse MUD URL '%s', ignoring: %m", rvalue);
@ -362,7 +423,7 @@ int config_parse_dhcp_send_option(
"Invalid DHCP option, ignoring assignment: %s", rvalue);
return 0;
}
if (u16 < 1 || u16 >= 65535) {
if (u16 < 1 || u16 >= UINT16_MAX) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"Invalid DHCP option, valid range is 1-65535, ignoring assignment: %s", rvalue);
return 0;
@ -374,7 +435,7 @@ int config_parse_dhcp_send_option(
"Invalid DHCP option, ignoring assignment: %s", rvalue);
return 0;
}
if (u8 < 1 || u8 >= 255) {
if (u8 < 1 || u8 >= UINT8_MAX) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue);
return 0;
@ -570,7 +631,7 @@ int config_parse_dhcp_request_options(
continue;
}
if (i < 1 || i >= 255) {
if (i < 1 || i >= UINT8_MAX) {
log_syntax(unit, LOG_ERR, filename, line, r,
"DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n);
continue;

View File

@ -50,5 +50,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_option);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options);

View File

@ -1605,60 +1605,6 @@ int config_parse_dhcp_black_listed_ip_address(
return 0;
}
int config_parse_dhcp_user_class(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
char ***l = data;
int r;
assert(l);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue)) {
*l = strv_free(*l);
return 0;
}
for (;;) {
_cleanup_free_ char *w = NULL;
r = extract_first_word(&rvalue, &w, NULL, 0);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to split user classes option, ignoring: %s", rvalue);
break;
}
if (r == 0)
break;
if (strlen(w) > 255) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"%s length is not in the range 1-255, ignoring.", w);
continue;
}
r = strv_push(l, w);
if (r < 0)
return log_oom();
w = NULL;
}
return 0;
}
int config_parse_dhcp_ip_service_type(
const char *unit,
const char *filename,

View File

@ -25,6 +25,5 @@ int dhcp4_set_promote_secondaries(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_black_listed_ip_address);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_ip_service_type);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_mud_url);

View File

@ -706,6 +706,12 @@ int dhcp6_configure(Link *link) {
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option);
}
if (link->network->dhcp6_user_class) {
r = sd_dhcp6_client_set_request_user_class(client, link->network->dhcp6_user_class);
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set user class: %m");
}
r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set callback: %m");

View File

@ -174,7 +174,7 @@ DHCPv4.RequestBroadcast, config_parse_bool,
DHCPv4.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
DHCPv4.MUDURL, config_parse_dhcp_mud_url, 0, 0
DHCPv4.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0
DHCPv4.UserClass, config_parse_dhcp_user_class, 0, offsetof(Network, dhcp_user_class)
DHCPv4.UserClass, config_parse_dhcp_user_class, AF_INET, offsetof(Network, dhcp_user_class)
DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid)
DHCPv4.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
DHCPv4.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
@ -194,6 +194,7 @@ DHCPv6.UseNTP, config_parse_bool,
DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
DHCPv6.MUDURL, config_parse_dhcp6_mud_url, 0, 0
DHCPv6.RequestOptions, config_parse_dhcp_request_options, AF_INET6, 0
DHCPv6.UserClass, config_parse_dhcp_user_class, AF_INET6, offsetof(Network, dhcp6_user_class)
DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0
DHCPv6.WithoutRA, config_parse_bool, 0, offsetof(Network, dhcp6_without_ra)
@ -384,7 +385,7 @@ DHCP.Hostname, config_parse_hostname,
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
DHCP.UserClass, config_parse_dhcp_user_class, 0, offsetof(Network, dhcp_user_class)
DHCP.UserClass, config_parse_dhcp_user_class, AF_INET, offsetof(Network, dhcp_user_class)
DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid)
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)

View File

@ -653,6 +653,7 @@ static Network *network_free(Network *network) {
set_free(network->dhcp6_request_options);
free(network->mac);
free(network->dhcp6_mudurl);
strv_free(network->dhcp6_user_class);
if (network->dhcp_acd)
sd_ipv4acd_unref(network->dhcp_acd);

View File

@ -132,6 +132,7 @@ struct Network {
bool dhcp6_without_ra;
uint8_t dhcp6_pd_length;
char *dhcp6_mudurl;
char **dhcp6_user_class;
struct in6_addr dhcp6_pd_address;
OrderedHashmap *dhcp6_client_send_options;
Set *dhcp6_request_options;

View File

@ -7,7 +7,9 @@
#include <unistd.h>
#include "alloc-util.h"
#include "blockdev-util.h"
#include "dissect-image.h"
#include "fd-util.h"
#include "main-func.h"
#include "process-util.h"
#include "signal-util.h"
@ -42,6 +44,7 @@ static int makefs(const char *type, const char *device) {
static int run(int argc, char *argv[]) {
_cleanup_free_ char *device = NULL, *type = NULL, *detected = NULL;
_cleanup_close_ int lock_fd = -1;
struct stat st;
int r;
@ -54,28 +57,31 @@ static int run(int argc, char *argv[]) {
/* type and device must be copied because makefs calls safe_fork, which clears argv[] */
type = strdup(argv[1]);
if (!type)
return -ENOMEM;
return log_oom();
device = strdup(argv[2]);
if (!device)
return -ENOMEM;
return log_oom();
if (stat(device, &st) < 0)
return log_error_errno(errno, "Failed to stat \"%s\": %m", device);
if (!S_ISBLK(st.st_mode))
if (S_ISBLK(st.st_mode)) {
/* Lock the device so that udev doesn't interfere with our work */
lock_fd = lock_whole_block_device(st.st_rdev, LOCK_EX);
if (lock_fd < 0)
return log_error_errno(lock_fd, "Failed to lock whole block device of \"%s\": %m", device);
} else
log_info("%s is not a block device.", device);
r = probe_filesystem(device, &detected);
if (r == -EUCLEAN)
return log_error_errno(r, "Ambiguous results of probing for file system on \"%s\", refusing to proceed.", device);
if (r < 0)
return log_warning_errno(r,
r == -EUCLEAN ?
"Cannot reliably determine probe \"%s\", refusing to proceed." :
"Failed to probe \"%s\": %m",
device);
return log_error_errno(r, "Failed to probe \"%s\": %m", device);
if (detected) {
log_info("%s is not empty (type %s), exiting", device, detected);
log_info("'%s' is not empty (contains file system of type %s), exiting.", device, detected);
return 0;
}

View File

@ -2233,7 +2233,6 @@ static int context_acquire_partition_uuids_and_labels(Context *context) {
LIST_FOREACH(partitions, p, context->partitions) {
assert(sd_id128_is_null(p->new_uuid));
assert(!p->new_label);
/* Never touch foreign partitions */
if (PARTITION_IS_FOREIGN(p)) {
@ -2256,6 +2255,9 @@ static int context_acquire_partition_uuids_and_labels(Context *context) {
return r;
}
if (p->new_label) /* Explicitly set by user? */
continue;
if (!isempty(p->current_label)) {
p->new_label = strdup(p->current_label); /* never change initialized labels */
if (!p->new_label)

View File

@ -75,10 +75,9 @@ int probe_filesystem(const char *node, char **ret_fstype) {
log_debug("No type detected on partition %s", node);
goto not_found;
}
if (r == -2) {
log_debug("Results ambiguous for partition %s", node);
return -EUCLEAN;
}
if (r == -2)
return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN),
"Results ambiguous for partition %s", node);
if (r != 0)
return errno_or_else(EIO);

View File

@ -138,7 +138,7 @@ static int apply_all(OrderedHashmap *sysctl_options) {
if (!pattern)
return log_oom();
k = glob_extend(&paths, pattern);
k = glob_extend(&paths, pattern, GLOB_NOCHECK);
if (k < 0) {
if (option->ignore_failure || ERRNO_IS_PRIVILEGE(k))
log_debug_errno(k, "Failed to resolve glob '%s', ignoring: %m",

View File

@ -4192,7 +4192,7 @@ static void print_status_info(
fs = !isempty(i->freezer_state) && !streq(i->freezer_state, "running") ? i->freezer_state : NULL;
if (fs)
printf(" %s(%s)%s", ansi_highlight_yellow(), fs, active_off);
printf(" %s(%s)%s", ansi_highlight_yellow(), fs, ansi_normal());
if (!isempty(i->result) && !streq(i->result, "success"))
printf(" (Result: %s)", i->result);

View File

@ -125,6 +125,10 @@ int sd_dhcp6_client_set_request_option(
int sd_dhcp6_client_set_request_mud_url(
sd_dhcp6_client *client,
const char *mudurl);
int sd_dhcp6_client_set_request_user_class(
sd_dhcp6_client *client,
char** user_class);
int sd_dhcp6_client_set_prefix_delegation_hint(
sd_dhcp6_client *client,
uint8_t prefixlen,

View File

@ -670,7 +670,7 @@ static void test_unlinkat_deallocate(void) {
assert_se(st.st_blocks > 0);
assert_se(st.st_nlink == 1);
assert_se(unlinkat_deallocate(AT_FDCWD, p, 0) >= 0);
assert_se(unlinkat_deallocate(AT_FDCWD, p, UNLINK_ERASE) >= 0);
assert_se(fstat(fd, &st) >= 0);
assert_se(IN_SET(st.st_size, 0, 6)); /* depending on whether hole punching worked the size will be 6
@ -850,6 +850,12 @@ static void test_path_is_encrypted_one(const char *p, int expect) {
int r;
r = path_is_encrypted(p);
if (r == -ENOENT) /* This might fail, if btrfs is used and we run in a container. In that case we
* cannot resolve the device node paths that BTRFS_IOC_DEV_INFO returns, because
* the device nodes are unlikely to exist in the container. But if we can't stat()
* them we cannot determine the dev_t of them, and thus cannot figure out if they
* are enrypted. Hence let's just ignore ENOENT here. */
return;
assert_se(r >= 0);
printf("%s encrypted: %s\n", p, yes_no(r));

View File

@ -115,6 +115,7 @@ WithoutRA=
MUDURL=
SendOption=
RequestOptions=
UserClass=
[Route]
Destination=
Protocol=