Compare commits

..

14 Commits

Author SHA1 Message Date
Chandradeep Dey 842067e675 homed: remove PAM_USER_UNKNOWN test in pam_sm_acct_mgmt
Why this change
---------------
Assumption - PAM's auth stack is properly configured.

Currently account pam_systemd_home.so returns PAM_SUCCESS for non
systemd-homed users, and a variety of return values (including
PAM_SUCCESS) for homed users.

account pam_unix returns PAM_AUTHINFO_UNAVAIL for systemd-homed
users, and a variety of return values (including PAM_AUTHINFO_UNAVAIL)
for normal users.

No possible combination in the pam stack can let us preserve the
various return values of the modules. For example, the configuration
mentioned in the manpage causes account pam_unix to never be reached
since pam_systemd_home just returns a success for ordinary users. Users
with expired passwords are allowed to log in because a check cannot be
made.

More configuration examples and why they don't work are mentioned
in #16906 and the downstream discussion linked there.

After this change
-----------------
account pam_unix will continue to return wrong value for homed users.
But we can skip the module conditionally using the return value from
account pam_systemd_home. We can already do this with the auth and
password modules.
2020-10-21 16:47:10 +02:00
Arian van Putten 429495163c cgtop: Display cpu time in microseonds with --raw
this makes the CPU time easily parseable; which was the goal
of --raw in the first place.

This only triggers if --raw is combined with --cpu=time
2020-10-21 14:29:48 +02:00
Zbigniew Jędrzejewski-Szmek 9d7b11fdc8
Merge pull request #17395 from keszybz/hwdb-drop-quotes
hwdb: drop quotes from XKB_FIXED_*= properties
2020-10-21 11:34:39 +02:00
Lennart Poettering aa5502bb33
Merge pull request #16444 from oniko/luks-detached-header
Add support for detached LUKS header on kernel cmd line
2020-10-21 10:41:11 +02:00
Lennart Poettering af918c4818 test-mountpoint-util: run test in private mount namespace
This creates a private mount namespace for test-mountpint-util, with all
propagation from the host turned off. This gives us the guarantee that
/proc/self/mountinfo remains fixed and constant while we operate,
removing potential races against other unrelated stuff running on the
system that changes the mount table.

Prompted-by: #17050

(I doubt this actually fixes 17050, this is mostly to make sure that we
aren't possibly affected by such races in our test)
2020-10-21 09:18:35 +02:00
Zbigniew Jędrzejewski-Szmek 327d8f3ab8 sd-hwdb: reduce variable scope, use periods 2020-10-20 17:23:40 +02:00
Zbigniew Jędrzejewski-Szmek afe87974dd sd-hwdb: allow empty properties
So far we didn't allow empty properties, but it makes sense to do so, for
example to distinguish empty data from lack of data. It also makes it easy to
override properties (back to the empty) value for specific cases.
2020-10-20 17:12:42 +02:00
Zbigniew Jędrzejewski-Szmek a136c2cdd8 hwdb: drop quotes from XKB_FIXED_*= properties
The properties are not unquoted by udev, so the quotes effectively became part
of the value.

Even though those properties were added quite a while ago
(086c001e29,
d7d31692bf), they never started being used
(because of issues with having multiple layouts), see
https://gitlab.gnome.org/GNOME/mutter/-/issues/906,
https://bugzilla.gnome.org/show_bug.cgi?id=775681.

Let's remove the quotes while we still can.

From https://bugzilla.gnome.org/show_bug.cgi?id=775681#c7:
> Note to self: the values for XKB_FIXED_LAYOUT and XKB_FIXED_VARIANT are
> quoted, meaning that we need to remove the quotes before passing the values
> from udev_device_get_property_value() to xkb_keymap_new_from_names()
> otherwise the compilation of the keymap fails (please don't ask how I found
> out...)
2020-10-20 08:37:07 +02:00
Ondrej Kozina 13445d9775 cryptsetup-generator: Add support for header device in crypttab 2020-09-25 17:01:36 +02:00
Ondrej Kozina a8574d0055 cryptsetup-generator: add detached LUKS header support
Adds support for LUKS detached header device on kernel
command line. It's introduced via extension to existing
luks.options 'header=' argument beyond colon (see examples
below). If LUKS header device is specified it's expected
to contain filesystem with LUKS header image on a path
specified in the first part of header specification.

The second parameter 'luks.data' specifies LUKS data device
supposed to be paired with detached LUKS header (note that
encrypted LUKS data device with detached header is unrecognisable
by standard blkid probe).

This adds support for LUKS encrypted rootfs partition with
detached header. It can also be used for initializing online LUKS2
encryption of data device.

Examples:
    luks.data=<luks_uuid>=/dev/sdz
    luks.data=<luks_uuid>=/dev/vg/lv
    luks.data=<luks_uuid>=/dev/mapper/lv
    luks.data=<luks_uuid>=PARTUUID=<part_uuid>
    luks.data=<luks_uuid>=PARTLABEL=<part_uuid>

    luks.options=<luks_uuid>=header=/header/path:UUID=<fs_uuid>
    luks.options=<luks_uuid>=header=/header/path:PARTUUID=<part_uuid>
    luks.options=<luks_uuid>=header=/header/path:PARTLABEL=<part_label>
    luks.options=<luks_uuid>=header=/header/path:LABEL=<fs_label>
    luks.options=<luks_uuid>=header=/header/path:/dev/sdx
    luks.options=<luks_uuid>=header=/header/path:/dev/vg/lv

The '/header/path' is considered to be relative location within
filesystem residing on the header device specified beyond colon
character
2020-09-25 17:01:36 +02:00
Ondrej Kozina fc6f1ad121 cryptsetup-generator: rename split_keyspec to split_locationspec
To be used later not only for splitting key specifications
2020-09-25 16:13:55 +02:00
Ondrej Kozina c3ee5b34f5 cryptsetup-generator: Add warn_uuid_invalid helper 2020-09-25 16:13:55 +02:00
Ondrej Kozina eb7d9aa391 cryptsetup-generator: rename and extend device mount helpers.
Those functions will be used later also for (u)mounting LUKS
header devices.
2020-09-25 16:13:55 +02:00
Ondrej Kozina 008fd4f9d4 cryptsetup-generator: use proper constant for uuid alphabet 2020-09-25 16:13:54 +02:00
11 changed files with 353 additions and 114 deletions

View File

@ -72,14 +72,14 @@
# A device with a fixed keyboard layout that must not be changed by # A device with a fixed keyboard layout that must not be changed by
# the desktop environment may specify that layout as: # the desktop environment may specify that layout as:
# XKB_FIXED_LAYOUT="us" # XKB_FIXED_LAYOUT=us
# XKB_FIXED_VARIANT="" # XKB_FIXED_VARIANT=
# Examples of such devices: the Yubikey or other key-code generating # Examples of such devices: the Yubikey or other key-code generating
# devices. # devices.
# A device where the scan code to key code mapping is insufficient and # A device where the scan code to key code mapping is insufficient and
# requires a special key code to symbol configuration may specify that with: # requires a special key code to symbol configuration may specify that with:
# XKB_FIXED_MODEL="xkbmodel" # XKB_FIXED_MODEL=xkbmodel
# Examples of such devices: Chromebooks where the top row is used for both # Examples of such devices: Chromebooks where the top row is used for both
# media and F1-F10 keys. # media and F1-F10 keys.
@ -1796,8 +1796,8 @@ evdev:input:b0003v1050p0111:*
evdev:input:b0003v1050p0116:* evdev:input:b0003v1050p0116:*
# OKE Electron Company USB barcode reader # OKE Electron Company USB barcode reader
evdev:input:b0003v05FEp1010:* evdev:input:b0003v05FEp1010:*
XKB_FIXED_LAYOUT="us" XKB_FIXED_LAYOUT=us
XKB_FIXED_VARIANT="" XKB_FIXED_VARIANT=
######################### LACK OF MODIFIER LEDS ############################ ######################### LACK OF MODIFIER LEDS ############################
# This section lists keyboard which do not have their own LEDs for some # This section lists keyboard which do not have their own LEDs for some
@ -1846,4 +1846,4 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX1Carbon3rd:*
# Chromebooks # Chromebooks
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnFalco:* evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnFalco:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPeppy:* evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPeppy:*
XKB_FIXED_MODEL="chromebook" XKB_FIXED_MODEL=chromebook

View File

@ -32,7 +32,7 @@ try:
from pyparsing import (Word, White, Literal, ParserElement, Regex, LineEnd, from pyparsing import (Word, White, Literal, ParserElement, Regex, LineEnd,
OneOrMore, Combine, Or, Optional, Suppress, Group, OneOrMore, Combine, Or, Optional, Suppress, Group,
nums, alphanums, printables, nums, alphanums, printables,
stringEnd, pythonStyleComment, QuotedString, stringEnd, pythonStyleComment,
ParseBaseException) ParseBaseException)
except ImportError: except ImportError:
print('pyparsing is not available') print('pyparsing is not available')
@ -54,7 +54,6 @@ EOL = LineEnd().suppress()
EMPTYLINE = LineEnd() EMPTYLINE = LineEnd()
COMMENTLINE = pythonStyleComment + EOL COMMENTLINE = pythonStyleComment + EOL
INTEGER = Word(nums) INTEGER = Word(nums)
STRING = QuotedString('"')
REAL = Combine((INTEGER + Optional('.' + Optional(INTEGER))) ^ ('.' + INTEGER)) REAL = Combine((INTEGER + Optional('.' + Optional(INTEGER))) ^ ('.' + INTEGER))
SIGNED_REAL = Combine(Optional(Word('-+')) + REAL) SIGNED_REAL = Combine(Optional(Word('-+')) + REAL)
UDEV_TAG = Word(string.ascii_uppercase, alphanums + '_') UDEV_TAG = Word(string.ascii_uppercase, alphanums + '_')
@ -94,7 +93,8 @@ def hwdb_grammar():
matchline = (matchline_typed | matchline_general) + EOL matchline = (matchline_typed | matchline_general) + EOL
propertyline = (White(' ', exact=1).suppress() + propertyline = (White(' ', exact=1).suppress() +
Combine(UDEV_TAG - '=' - Word(alphanums + '_=:@*.!-;, "') - Optional(pythonStyleComment)) + Combine(UDEV_TAG - '=' - Optional(Word(alphanums + '_=:@*.!-;, "'))
- Optional(pythonStyleComment)) +
EOL) EOL)
propertycomment = White(' ', exact=1) + pythonStyleComment + EOL propertycomment = White(' ', exact=1) + pythonStyleComment + EOL
@ -114,6 +114,7 @@ def property_grammar():
dpi_setting = (Optional('*')('DEFAULT') + INTEGER('DPI') + Suppress('@') + INTEGER('HZ'))('SETTINGS*') dpi_setting = (Optional('*')('DEFAULT') + INTEGER('DPI') + Suppress('@') + INTEGER('HZ'))('SETTINGS*')
mount_matrix_row = SIGNED_REAL + ',' + SIGNED_REAL + ',' + SIGNED_REAL mount_matrix_row = SIGNED_REAL + ',' + SIGNED_REAL + ',' + SIGNED_REAL
mount_matrix = (mount_matrix_row + ';' + mount_matrix_row + ';' + mount_matrix_row)('MOUNT_MATRIX') mount_matrix = (mount_matrix_row + ';' + mount_matrix_row + ';' + mount_matrix_row)('MOUNT_MATRIX')
xkb_setting = Optional(Word(alphanums + '+-/@._'))
props = (('MOUSE_DPI', Group(OneOrMore(dpi_setting))), props = (('MOUSE_DPI', Group(OneOrMore(dpi_setting))),
('MOUSE_WHEEL_CLICK_ANGLE', INTEGER), ('MOUSE_WHEEL_CLICK_ANGLE', INTEGER),
@ -138,9 +139,9 @@ def property_grammar():
('POINTINGSTICK_CONST_ACCEL', REAL), ('POINTINGSTICK_CONST_ACCEL', REAL),
('ID_INPUT_JOYSTICK_INTEGRATION', Or(('internal', 'external'))), ('ID_INPUT_JOYSTICK_INTEGRATION', Or(('internal', 'external'))),
('ID_INPUT_TOUCHPAD_INTEGRATION', Or(('internal', 'external'))), ('ID_INPUT_TOUCHPAD_INTEGRATION', Or(('internal', 'external'))),
('XKB_FIXED_LAYOUT', STRING), ('XKB_FIXED_LAYOUT', xkb_setting),
('XKB_FIXED_VARIANT', STRING), ('XKB_FIXED_VARIANT', xkb_setting),
('XKB_FIXED_MODEL', STRING), ('XKB_FIXED_MODEL', xkb_setting),
('KEYBOARD_LED_NUMLOCK', Literal('0')), ('KEYBOARD_LED_NUMLOCK', Literal('0')),
('KEYBOARD_LED_CAPSLOCK', Literal('0')), ('KEYBOARD_LED_CAPSLOCK', Literal('0')),
('ACCEL_MOUNT_MATRIX', mount_matrix), ('ACCEL_MOUNT_MATRIX', mount_matrix),

View File

@ -112,7 +112,12 @@
relevant for LUKS devices. See relevant for LUKS devices. See
<citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry> <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for possible values and the default value of this for possible values and the default value of this
option.</para></listitem> option.</para>
<para>Optionally, the path may be followed by <literal>:</literal> and an fstab device specification
(e.g. starting with <literal>UUID=</literal> or similar); in which case, the path is relative to the
device file system root. The device gets mounted automatically for LUKS device activation duration only.
</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -130,7 +130,7 @@
<term><option>-r</option></term> <term><option>-r</option></term>
<term><option>--raw</option></term> <term><option>--raw</option></term>
<listitem><para>Format byte counts (as in memory usage and I/O metrics) <listitem><para>Format byte counts (as in memory usage and I/O metrics) and CPU time
with raw numeric values rather than human-readable with raw numeric values rather than human-readable
numbers.</para></listitem> numbers.</para></listitem>
</varlistentry> </varlistentry>

View File

@ -105,6 +105,9 @@
LUKS device given by the UUID appear under the provided LUKS device given by the UUID appear under the provided
name.</para> name.</para>
<para>This parameter is the analogue of the first <citerefentry><refentrytitle>crypttab</refentrytitle>
<manvolnum>5</manvolnum></citerefentry> field <replaceable>volume-name</replaceable>.</para>
<para><varname>rd.luks.name=</varname> is honored only by <para><varname>rd.luks.name=</varname> is honored only by
initial RAM disk (initrd) while <varname>luks.name=</varname> initial RAM disk (initrd) while <varname>luks.name=</varname>
is honored by both the main system and the initrd.</para> is honored by both the main system and the initrd.</para>
@ -112,20 +115,30 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><varname>luks.options=</varname></term> <term><varname>luks.data=</varname></term>
<term><varname>rd.luks.options=</varname></term> <term><varname>rd.luks.data=</varname></term>
<listitem><para>Takes a LUKS super block UUID followed by an <listitem><para>Takes a LUKS super block UUID followed by a <literal>=</literal> and a block device
<literal>=</literal> and a string of options separated by specification for device hosting encrypted data.</para>
commas as argument. This will override the options for the
given UUID.</para> <para>For those entries specified with <varname>rd.luks.uuid=</varname> or
<para>If only a list of options, without an UUID, is <varname>luks.uuid=</varname>, the data device will be set to the one specified by
specified, they apply to any UUIDs not specified elsewhere, <varname>rd.luks.data=</varname> or <varname>luks.data=</varname> of the corresponding UUID.</para>
and without an entry in
<filename>/etc/crypttab</filename>.</para><para> <para>LUKS data device parameter is usefull for specifying encrypted data devices with detached headers specified in
<varname>rd.luks.options=</varname> is honored only by initial <varname>luks.options</varname> entry containing <literal>header=</literal> argument. For example,
RAM disk (initrd) while <varname>luks.options=</varname> is <varname>rd.luks.uuid=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40
honored by both the main system and the initrd.</para> <varname>rd.luks.options=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40=header=/path/to/luks.hdr
<varname>rd.luks.data=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40=/dev/sdx.
Hence, in this case, we will attempt to unlock LUKS device assembled from data device <literal>/dev/sdx</literal>
and LUKS header (metadata) put in <literal>/path/to/luks.hdr</literal> file. This syntax is for now
only supported on a per-device basis, i.e. you have to specify LUKS device UUID.</para>
<para>This parameter is the analogue of the second <citerefentry><refentrytitle>crypttab</refentrytitle>
<manvolnum>5</manvolnum></citerefentry> field <replaceable>encrypted-device</replaceable>.</para>
<para><varname>rd.luks.data=</varname> is honored only by initial RAM disk (initrd) while
<varname>luks.data=</varname> is honored by both the main system and the initrd.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -157,6 +170,9 @@
This syntax is for now only supported on a per-device basis, This syntax is for now only supported on a per-device basis,
i.e. you have to specify LUKS device UUID.</para> i.e. you have to specify LUKS device UUID.</para>
<para>This parameter is the analogue of the third <citerefentry><refentrytitle>crypttab</refentrytitle>
<manvolnum>5</manvolnum></citerefentry> field <replaceable>key-file</replaceable>.</para>
<para><varname>rd.luks.key=</varname> <para><varname>rd.luks.key=</varname>
is honored only by initial RAM disk is honored only by initial RAM disk
(initrd) while (initrd) while
@ -165,6 +181,44 @@
the initrd.</para> the initrd.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>luks.options=</varname></term>
<term><varname>rd.luks.options=</varname></term>
<listitem><para>Takes a LUKS super block UUID followed by an
<literal>=</literal> and a string of options separated by
commas as argument. This will override the options for the
given UUID.</para>
<para>If only a list of options, without an UUID, is
specified, they apply to any UUIDs not specified elsewhere,
and without an entry in
<filename>/etc/crypttab</filename>.</para>
<para>This parameter is the analogue of the fourth <citerefentry><refentrytitle>crypttab</refentrytitle>
<manvolnum>5</manvolnum></citerefentry> field <replaceable>options</replaceable>.</para>
<para>It is possible to specify an external device which
should be mounted before we attempt to unlock the LUKS device.
systemd-cryptsetup will assemble LUKS device by combining
data device specified in <varname>luks.data</varname> with
detached LUKS header found in <literal>header=</literal>
argument. For example,
<varname>rd.luks.uuid=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40
<varname>rd.luks.options=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40=header=/luks.hdr:LABEL=hdrdev
<varname>rd.luks.data=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40=/dev/sdx.
Hence, in this case, we will attempt to mount file system
residing on the block device with label <literal>hdrdev</literal>, and look
for <literal>luks.hdr</literal> on that file system. Said header will be used
to unlock (decrypt) encrypted data stored on /dev/sdx.
This syntax is for now only supported on a per-device basis,
i.e. you have to specify LUKS device UUID.</para>
<para><varname>rd.luks.options=</varname> is honored only by initial
RAM disk (initrd) while <varname>luks.options=</varname> is
honored by both the main system and the initrd.</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>

View File

@ -281,6 +281,12 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
MAX(_c, z); \ MAX(_c, z); \
}) })
#define MAX4(x, y, z, a) \
({ \
const typeof(x) _d = MAX3(x, y, z); \
MAX(_d, a); \
})
#undef MIN #undef MIN
#define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b)) #define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b))
#define __MIN(aq, a, bq, b) \ #define __MIN(aq, a, bq, b) \

View File

@ -91,6 +91,15 @@ static Group *group_free(Group *g) {
return mfree(g); return mfree(g);
} }
static const char *maybe_format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
if (arg_raw) {
snprintf(buf, l, USEC_FMT, t);
return buf;
}
return format_timespan(buf, l, t, accuracy);
}
static const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, uint64_t t) { static const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, uint64_t t) {
if (!is_valid) if (!is_valid)
return "-"; return "-";
@ -586,7 +595,7 @@ static void display(Hashmap *a) {
Group **array; Group **array;
signed path_columns; signed path_columns;
unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 3; /* 3 for ellipsize() to work properly */ unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 3; /* 3 for ellipsize() to work properly */
char buffer[MAX3(21U, FORMAT_BYTES_MAX, FORMAT_TIMESPAN_MAX)]; char buffer[MAX4(21U, FORMAT_BYTES_MAX, FORMAT_TIMESPAN_MAX, DECIMAL_STR_MAX(usec_t))];
assert(a); assert(a);
@ -605,7 +614,7 @@ static void display(Hashmap *a) {
for (j = 0; j < n; j++) { for (j = 0; j < n; j++) {
unsigned cputlen, pathtlen; unsigned cputlen, pathtlen;
format_timespan(buffer, sizeof(buffer), (usec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0); maybe_format_timespan(buffer, sizeof(buffer), (usec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0);
cputlen = strlen(buffer); cputlen = strlen(buffer);
maxtcpu = MAX(maxtcpu, cputlen); maxtcpu = MAX(maxtcpu, cputlen);
@ -674,7 +683,7 @@ static void display(Hashmap *a) {
else else
fputs(" -", stdout); fputs(" -", stdout);
} else } else
printf(" %*s", maxtcpu, format_timespan(buffer, sizeof(buffer), (usec_t) (g->cpu_usage / NSEC_PER_USEC), 0)); printf(" %*s", maxtcpu, maybe_format_timespan(buffer, sizeof(buffer), (usec_t) (g->cpu_usage / NSEC_PER_USEC), 0));
printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->memory_valid, g->memory)); printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->memory_valid, g->memory));
printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_input_bps)); printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_input_bps));

View File

@ -29,6 +29,8 @@ typedef struct crypto_device {
char *uuid; char *uuid;
char *keyfile; char *keyfile;
char *keydev; char *keydev;
char *headerdev;
char *datadev;
char *name; char *name;
char *options; char *options;
bool create; bool create;
@ -48,62 +50,64 @@ STATIC_DESTRUCTOR_REGISTER(arg_disks, hashmap_freep);
STATIC_DESTRUCTOR_REGISTER(arg_default_options, freep); STATIC_DESTRUCTOR_REGISTER(arg_default_options, freep);
STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile, freep); STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile, freep);
static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_keydev) { static int split_locationspec(const char *locationspec, char **ret_file, char **ret_device) {
_cleanup_free_ char *keyfile = NULL, *keydev = NULL; _cleanup_free_ char *file = NULL, *device = NULL;
const char *c; const char *c;
assert(ret_keyfile); assert(ret_file);
assert(ret_keydev); assert(ret_device);
if (!keyspec) { if (!locationspec) {
*ret_keyfile = *ret_keydev = NULL; *ret_file = *ret_device = NULL;
return 0; return 0;
} }
c = strrchr(keyspec, ':'); c = strrchr(locationspec, ':');
if (c) { if (c) {
/* The keydev part has to be either an absolute path to device node (/dev/something, /* The device part has to be either an absolute path to device node (/dev/something,
* /dev/foo/something, or even possibly /dev/foo/something:part), or a fstab device * /dev/foo/something, or even possibly /dev/foo/something:part), or a fstab device
* specification starting with LABEL= or similar. The keyfile part has the same syntax. * specification starting with LABEL= or similar. The file part has the same syntax.
* *
* Let's try to guess if the second part looks like a keydev specification, or just part of a * Let's try to guess if the second part looks like a device specification, or just part of a
* filename with a colon. fstab_node_to_udev_node() will convert the fstab device syntax to * filename with a colon. fstab_node_to_udev_node() will convert the fstab device syntax to
* an absolute path. If we didn't get an absolute path, assume that it is just part of the * an absolute path. If we didn't get an absolute path, assume that it is just part of the
* first keyfile argument. */ * first file argument. */
keydev = fstab_node_to_udev_node(c + 1); device = fstab_node_to_udev_node(c + 1);
if (!keydev) if (!device)
return log_oom(); return log_oom();
if (path_is_absolute(keydev)) if (path_is_absolute(device))
keyfile = strndup(keyspec, c-keyspec); file = strndup(locationspec, c-locationspec);
else { else {
log_debug("Keyspec argument contains a colon, but \"%s\" doesn't look like a device specification.\n" log_debug("Location specification argument contains a colon, but \"%s\" doesn't look like a device specification.\n"
"Assuming that \"%s\" is a single device specification.", "Assuming that \"%s\" is a single device specification.",
c + 1, keyspec); c + 1, locationspec);
keydev = mfree(keydev); device = mfree(device);
c = NULL; c = NULL;
} }
} }
if (!c) if (!c)
/* No keydev specified */ /* No device specified */
keyfile = strdup(keyspec); file = strdup(locationspec);
if (!keyfile) if (!file)
return log_oom(); return log_oom();
*ret_keyfile = TAKE_PTR(keyfile); *ret_file = TAKE_PTR(file);
*ret_keydev = TAKE_PTR(keydev); *ret_device = TAKE_PTR(device);
return 0; return 0;
} }
static int generate_keydev_mount( static int generate_device_mount(
const char *name, const char *name,
const char *keydev, const char *device,
const char *keydev_timeout, const char *type_prefix, /* "keydev" or "headerdev" */
const char *device_timeout,
bool canfail, bool canfail,
bool readonly,
char **unit, char **unit,
char **mount) { char **mount) {
@ -113,7 +117,7 @@ static int generate_keydev_mount(
usec_t timeout_us; usec_t timeout_us;
assert(name); assert(name);
assert(keydev); assert(device);
assert(unit); assert(unit);
assert(mount); assert(mount);
@ -129,7 +133,7 @@ static int generate_keydev_mount(
if (!name_escaped) if (!name_escaped)
return -ENOMEM; return -ENOMEM;
where = strjoin(arg_runtime_directory, "/keydev-", name_escaped); where = strjoin(arg_runtime_directory, "/", type_prefix, "-", name_escaped);
if (!where) if (!where)
return -ENOMEM; return -ENOMEM;
@ -151,23 +155,23 @@ static int generate_keydev_mount(
"[Mount]\n" "[Mount]\n"
"What=%s\n" "What=%s\n"
"Where=%s\n" "Where=%s\n"
"Options=ro%s\n", keydev, where, canfail ? ",nofail" : ""); "Options=%s%s\n", device, where, readonly ? "ro" : "rw", canfail ? ",nofail" : "");
if (keydev_timeout) { if (device_timeout) {
r = parse_sec_fix_0(keydev_timeout, &timeout_us); r = parse_sec_fix_0(device_timeout, &timeout_us);
if (r >= 0) { if (r >= 0) {
r = unit_name_from_path(keydev, ".device", &device_unit); r = unit_name_from_path(device, ".device", &device_unit);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m"); return log_error_errno(r, "Failed to generate unit name: %m");
r = write_drop_in_format(arg_dest, device_unit, 90, "device-timeout", r = write_drop_in_format(arg_dest, device_unit, 90, "device-timeout",
"# Automatically generated by systemd-cryptsetup-generator \n\n" "# Automatically generated by systemd-cryptsetup-generator \n\n"
"[Unit]\nJobRunningTimeoutSec=%s", keydev_timeout); "[Unit]\nJobRunningTimeoutSec=%s", device_timeout);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to write device drop-in: %m"); return log_error_errno(r, "Failed to write device drop-in: %m");
} else } else
log_warning_errno(r, "Failed to parse %s, ignoring: %m", keydev_timeout); log_warning_errno(r, "Failed to parse %s, ignoring: %m", device_timeout);
} }
@ -181,8 +185,9 @@ static int generate_keydev_mount(
return 0; return 0;
} }
static int generate_keydev_umount(const char *name, static int generate_device_umount(const char *name,
const char *keydev_mount, const char *device_mount,
const char *type_prefix, /* "keydev" or "headerdev" */
char **ret_umount_unit) { char **ret_umount_unit) {
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *u = NULL, *name_escaped = NULL, *mount = NULL; _cleanup_free_ char *u = NULL, *name_escaped = NULL, *mount = NULL;
@ -195,11 +200,11 @@ static int generate_keydev_umount(const char *name,
if (!name_escaped) if (!name_escaped)
return -ENOMEM; return -ENOMEM;
u = strjoin("keydev-", name_escaped, "-umount.service"); u = strjoin(type_prefix, "-", name_escaped, "-umount.service");
if (!u) if (!u)
return -ENOMEM; return -ENOMEM;
r = unit_name_from_path(keydev_mount, ".mount", &mount); r = unit_name_from_path(device_mount, ".mount", &mount);
if (r < 0) if (r < 0)
return r; return r;
@ -212,7 +217,7 @@ static int generate_keydev_umount(const char *name,
"DefaultDependencies=no\n" "DefaultDependencies=no\n"
"After=%s\n\n" "After=%s\n\n"
"[Service]\n" "[Service]\n"
"ExecStart=-" UMOUNT_PATH " %s\n\n", mount, keydev_mount); "ExecStart=-" UMOUNT_PATH " %s\n\n", mount, device_mount);
r = fflush_and_check(f); r = fflush_and_check(f);
if (r < 0) if (r < 0)
@ -274,13 +279,14 @@ static int create_disk(
const char *device, const char *device,
const char *password, const char *password,
const char *keydev, const char *keydev,
const char *headerdev,
const char *options, const char *options,
const char *source) { const char *source) {
_cleanup_free_ char *n = NULL, *d = NULL, *u = NULL, *e = NULL, _cleanup_free_ char *n = NULL, *d = NULL, *u = NULL, *e = NULL,
*keydev_mount = NULL, *keyfile_timeout_value = NULL, *keydev_mount = NULL, *keyfile_timeout_value = NULL,
*filtered = NULL, *u_escaped = NULL, *name_escaped = NULL, *header_path = NULL, *password_buffer = NULL, *filtered = NULL, *u_escaped = NULL, *name_escaped = NULL, *header_path = NULL, *password_buffer = NULL,
*tmp_fstype = NULL; *tmp_fstype = NULL, *filtered_header = NULL, *headerdev_mount = NULL;
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
const char *dmname; const char *dmname;
bool noauto, nofail, swap, netdev, attach_in_initrd; bool noauto, nofail, swap, netdev, attach_in_initrd;
@ -299,7 +305,12 @@ static int create_disk(
if (keyfile_can_timeout < 0) if (keyfile_can_timeout < 0)
return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m"); return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m");
detached_header = fstab_filter_options(options, "header\0", NULL, &header_path, NULL); detached_header = fstab_filter_options(
options,
"header\0",
NULL,
&header_path,
headerdev ? &filtered_header : NULL);
if (detached_header < 0) if (detached_header < 0)
return log_error_errno(detached_header, "Failed to parse header= option value: %m"); return log_error_errno(detached_header, "Failed to parse header= option value: %m");
@ -358,11 +369,19 @@ static int create_disk(
if (keydev) { if (keydev) {
_cleanup_free_ char *unit = NULL, *umount_unit = NULL; _cleanup_free_ char *unit = NULL, *umount_unit = NULL;
r = generate_keydev_mount(name, keydev, keyfile_timeout_value, keyfile_can_timeout > 0, &unit, &keydev_mount); r = generate_device_mount(
name,
keydev,
"keydev",
keyfile_timeout_value,
/* canfail = */ keyfile_can_timeout > 0,
/* readonly= */ true,
&unit,
&keydev_mount);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to generate keydev mount unit: %m"); return log_error_errno(r, "Failed to generate keydev mount unit: %m");
r = generate_keydev_umount(name, keydev_mount, &umount_unit); r = generate_device_umount(name, keydev_mount, "keydev", &umount_unit);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to generate keydev umount unit: %m"); return log_error_errno(r, "Failed to generate keydev umount unit: %m");
@ -387,6 +406,55 @@ static int create_disk(
); );
} }
if (headerdev) {
_cleanup_free_ char *unit = NULL, *umount_unit = NULL, *p = NULL;
r = generate_device_mount(
name,
headerdev,
"headerdev",
NULL,
/* canfail= */ false, /* header is always necessary */
/* readonly= */ false, /* LUKS2 recovery requires rw header access */
&unit,
&headerdev_mount);
if (r < 0)
return log_error_errno(r, "Failed to generate header device mount unit: %m");
r = generate_device_umount(name, headerdev_mount, "headerdev", &umount_unit);
if (r < 0)
return log_error_errno(r, "Failed to generate header device umount unit: %m");
p = path_join(headerdev_mount, header_path);
if (!p)
return log_oom();
free_and_replace(header_path, p);
if (isempty(filtered_header))
p = strjoin("header=", header_path);
else
p = strjoin(filtered_header, ",header=", header_path);
if (!p)
return log_oom();
free_and_replace(filtered_header, p);
options = filtered_header;
fprintf(f, "After=%s\n"
"Requires=%s\n", unit, unit);
if (umount_unit) {
fprintf(f,
"Wants=%s\n"
"Before=%s\n",
umount_unit,
umount_unit
);
}
}
if (!nofail) if (!nofail)
fprintf(f, fprintf(f,
"Before=%s\n", "Before=%s\n",
@ -399,7 +467,7 @@ static int create_disk(
} }
/* Check if a header option was specified */ /* Check if a header option was specified */
if (detached_header > 0) { if (detached_header > 0 && !headerdev) {
r = print_dependencies(f, header_path); r = print_dependencies(f, header_path);
if (r < 0) if (r < 0)
return r; return r;
@ -514,6 +582,52 @@ static crypto_device *get_crypto_device(const char *uuid) {
return d; return d;
} }
static bool warn_uuid_invalid(const char *uuid, const char *key) {
assert(key);
if (!id128_is_valid(uuid)) {
log_warning("Failed to parse %s= kernel command line switch. UUID is invalid, ignoring.", key);
return true;
}
return false;
}
static int filter_header_device(const char *options,
char **ret_headerdev,
char **ret_filtered_headerdev_options) {
int r;
_cleanup_free_ char *headerfile = NULL, *headerdev = NULL, *headerspec = NULL,
*filtered_headerdev = NULL, *filtered_headerspec = NULL;
assert(ret_headerdev);
assert(ret_filtered_headerdev_options);
r = fstab_filter_options(options, "header\0", NULL, &headerspec, &filtered_headerspec);
if (r < 0)
return log_error_errno(r, "Failed to parse header= option value: %m");
if (r > 0) {
r = split_locationspec(headerspec, &headerfile, &headerdev);
if (r < 0)
return r;
if (isempty(filtered_headerspec))
filtered_headerdev = strjoin("header=", headerfile);
else
filtered_headerdev = strjoin(filtered_headerspec, ",header=", headerfile);
if (!filtered_headerdev)
return log_oom();
} else
filtered_headerdev = TAKE_PTR(filtered_headerspec);
*ret_filtered_headerdev_options = TAKE_PTR(filtered_headerdev);
*ret_headerdev = TAKE_PTR(headerdev);
return 0;
}
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
_cleanup_free_ char *uuid = NULL, *uuid_value = NULL; _cleanup_free_ char *uuid = NULL, *uuid_value = NULL;
crypto_device *d; crypto_device *d;
@ -547,20 +661,28 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
d->create = arg_allow_list = true; d->create = arg_allow_list = true;
} else if (streq(key, "luks.options")) { } else if (streq(key, "luks.options")) {
_cleanup_free_ char *headerdev = NULL, *filtered_headerdev_options = NULL;
if (proc_cmdline_value_missing(key, value)) if (proc_cmdline_value_missing(key, value))
return 0; return 0;
r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value); r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
if (r == 2) { if (r != 2)
return free_and_strdup(&arg_default_options, value) < 0 ? log_oom() : 0;
if (warn_uuid_invalid(uuid, key))
return 0;
d = get_crypto_device(uuid); d = get_crypto_device(uuid);
if (!d) if (!d)
return log_oom(); return log_oom();
free_and_replace(d->options, uuid_value); r = filter_header_device(uuid_value, &headerdev, &filtered_headerdev_options);
} else if (free_and_strdup(&arg_default_options, value) < 0) if (r < 0)
return log_oom(); return r;
free_and_replace(d->options, filtered_headerdev_options);
free_and_replace(d->headerdev, headerdev);
} else if (streq(key, "luks.key")) { } else if (streq(key, "luks.key")) {
size_t n; size_t n;
_cleanup_free_ char *keyfile = NULL, *keydev = NULL; _cleanup_free_ char *keyfile = NULL, *keydev = NULL;
@ -569,7 +691,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (proc_cmdline_value_missing(key, value)) if (proc_cmdline_value_missing(key, value))
return 0; return 0;
n = strspn(value, LETTERS DIGITS "-"); n = strspn(value, ALPHANUMERICAL "-");
if (value[n] != '=') { if (value[n] != '=') {
if (free_and_strdup(&arg_default_keyfile, value) < 0) if (free_and_strdup(&arg_default_keyfile, value) < 0)
return log_oom(); return log_oom();
@ -580,23 +702,49 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (!uuid) if (!uuid)
return log_oom(); return log_oom();
if (!id128_is_valid(uuid)) { if (warn_uuid_invalid(uuid, key))
log_warning("Failed to parse luks.key= kernel command line switch. UUID is invalid, ignoring.");
return 0; return 0;
}
d = get_crypto_device(uuid); d = get_crypto_device(uuid);
if (!d) if (!d)
return log_oom(); return log_oom();
keyspec = value + n + 1; keyspec = value + n + 1;
r = split_keyspec(keyspec, &keyfile, &keydev); r = split_locationspec(keyspec, &keyfile, &keydev);
if (r < 0) if (r < 0)
return r; return r;
free_and_replace(d->keyfile, keyfile); free_and_replace(d->keyfile, keyfile);
free_and_replace(d->keydev, keydev); free_and_replace(d->keydev, keydev);
} else if (streq(key, "luks.data")) {
size_t n;
_cleanup_free_ char *datadev = NULL;
if (proc_cmdline_value_missing(key, value))
return 0;
n = strspn(value, ALPHANUMERICAL "-");
if (value[n] != '=') {
log_warning("Failed to parse luks.data= kernel command line switch. UUID is invalid, ignoring.");
return 0;
}
uuid = strndup(value, n);
if (!uuid)
return log_oom();
if (warn_uuid_invalid(uuid, key))
return 0;
d = get_crypto_device(uuid);
if (!d)
return log_oom();
datadev = fstab_node_to_udev_node(value + n + 1);
if (!datadev)
return log_oom();
free_and_replace(d->datadev, datadev);
} else if (streq(key, "luks.name")) { } else if (streq(key, "luks.name")) {
if (proc_cmdline_value_missing(key, value)) if (proc_cmdline_value_missing(key, value))
@ -634,7 +782,8 @@ static int add_crypttab_devices(void) {
} }
for (;;) { for (;;) {
_cleanup_free_ char *line = NULL, *name = NULL, *device = NULL, *keyspec = NULL, *options = NULL, *keyfile = NULL, *keydev = NULL; _cleanup_free_ char *line = NULL, *name = NULL, *device = NULL, *keyspec = NULL, *options = NULL,
*keyfile = NULL, *keydev = NULL, *headerdev = NULL, *filtered_header = NULL;
crypto_device *d = NULL; crypto_device *d = NULL;
char *l, *uuid; char *l, *uuid;
int k; int k;
@ -670,11 +819,24 @@ static int add_crypttab_devices(void) {
continue; continue;
} }
r = split_keyspec(keyspec, &keyfile, &keydev); r = split_locationspec(keyspec, &keyfile, &keydev);
if (r < 0) if (r < 0)
return r; return r;
r = create_disk(name, device, keyfile, keydev, (d && d->options) ? d->options : options, arg_crypttab); if (options && (!d || !d->options)) {
r = filter_header_device(options, &headerdev, &filtered_header);
if (r < 0)
return r;
free_and_replace(options, filtered_header);
}
r = create_disk(name,
device,
keyfile,
keydev,
(d && d->options) ? d->headerdev : headerdev,
(d && d->options) ? d->options : options,
arg_crypttab);
if (r < 0) if (r < 0)
return r; return r;
@ -706,9 +868,10 @@ static int add_proc_cmdline_devices(void) {
return log_oom(); return log_oom();
r = create_disk(d->name, r = create_disk(d->name,
device, d->datadev ?: device,
d->keyfile ?: arg_default_keyfile, d->keyfile ?: arg_default_keyfile,
d->keydev, d->keydev,
d->headerdev,
d->options ?: arg_default_options, d->options ?: arg_default_options,
"/proc/cmdline"); "/proc/cmdline");
if (r < 0) if (r < 0)

View File

@ -833,8 +833,6 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt(
pam_syslog(handle, LOG_DEBUG, "pam-systemd-homed account management"); pam_syslog(handle, LOG_DEBUG, "pam-systemd-homed account management");
r = acquire_home(handle, /* please_authenticate = */ false, please_suspend, debug); r = acquire_home(handle, /* please_authenticate = */ false, please_suspend, debug);
if (r == PAM_USER_UNKNOWN)
return PAM_SUCCESS; /* we don't have anything to say about users we don't manage */
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;

View File

@ -105,12 +105,10 @@ static struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) {
} }
static void trie_node_cleanup(struct trie_node *node) { static void trie_node_cleanup(struct trie_node *node) {
size_t i;
if (!node) if (!node)
return; return;
for (i = 0; i < node->children_count; i++) for (size_t i = 0; i < node->children_count; i++)
trie_node_cleanup(node->children[i].child); trie_node_cleanup(node->children[i].child);
free(node->children); free(node->children);
free(node->values); free(node->values);
@ -191,10 +189,9 @@ static int trie_node_add_value(struct trie *trie, struct trie_node *node,
static int trie_insert(struct trie *trie, struct trie_node *node, const char *search, static int trie_insert(struct trie *trie, struct trie_node *node, const char *search,
const char *key, const char *value, const char *key, const char *value,
const char *filename, uint16_t file_priority, uint32_t line_number, bool compat) { const char *filename, uint16_t file_priority, uint32_t line_number, bool compat) {
size_t i = 0;
int r = 0; int r = 0;
for (;;) { for (size_t i = 0;; i++) {
size_t p; size_t p;
uint8_t c; uint8_t c;
struct trie_node *child; struct trie_node *child;
@ -273,7 +270,6 @@ static int trie_insert(struct trie *trie, struct trie_node *node, const char *se
} }
node = child; node = child;
i++;
} }
} }
@ -289,20 +285,17 @@ struct trie_f {
/* calculate the storage space for the nodes, children arrays, value arrays */ /* calculate the storage space for the nodes, children arrays, value arrays */
static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node, bool compat) { static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node, bool compat) {
uint64_t i; for (uint64_t i = 0; i < node->children_count; i++)
for (i = 0; i < node->children_count; i++)
trie_store_nodes_size(trie, node->children[i].child, compat); trie_store_nodes_size(trie, node->children[i].child, compat);
trie->strings_off += sizeof(struct trie_node_f); trie->strings_off += sizeof(struct trie_node_f);
for (i = 0; i < node->children_count; i++) for (uint64_t i = 0; i < node->children_count; i++)
trie->strings_off += sizeof(struct trie_child_entry_f); trie->strings_off += sizeof(struct trie_child_entry_f);
for (i = 0; i < node->values_count; i++) for (uint64_t i = 0; i < node->values_count; i++)
trie->strings_off += compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f); trie->strings_off += compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f);
} }
static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, bool compat) { static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, bool compat) {
uint64_t i;
struct trie_node_f n = { struct trie_node_f n = {
.prefix_off = htole64(trie->strings_off + node->prefix_off), .prefix_off = htole64(trie->strings_off + node->prefix_off),
.children_count = node->children_count, .children_count = node->children_count,
@ -318,7 +311,7 @@ static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, boo
} }
/* post-order recursion */ /* post-order recursion */
for (i = 0; i < node->children_count; i++) { for (uint64_t i = 0; i < node->children_count; i++) {
int64_t child_off; int64_t child_off;
child_off = trie_store_nodes(trie, node->children[i].child, compat); child_off = trie_store_nodes(trie, node->children[i].child, compat);
@ -343,7 +336,7 @@ static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, boo
} }
/* append values array */ /* append values array */
for (i = 0; i < node->values_count; i++) { for (uint64_t i = 0; i < node->values_count; i++) {
struct trie_value_entry2_f v = { struct trie_value_entry2_f v = {
.key_off = htole64(trie->strings_off + node->values[i].key_off), .key_off = htole64(trie->strings_off + node->values[i].key_off),
.value_off = htole64(trie->strings_off + node->values[i].value_off), .value_off = htole64(trie->strings_off + node->values[i].value_off),
@ -447,7 +440,7 @@ static int insert_data(struct trie *trie, char **match_list, char *line, const c
value = strchr(line, '='); value = strchr(line, '=');
if (!value) if (!value)
return log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL), return log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL),
"Key-value pair expected but got \"%s\", ignoring", line); "Key-value pair expected but got \"%s\", ignoring.", line);
value[0] = '\0'; value[0] = '\0';
value++; value++;
@ -456,10 +449,9 @@ static int insert_data(struct trie *trie, char **match_list, char *line, const c
while (isblank(line[0]) && isblank(line[1])) while (isblank(line[0]) && isblank(line[1]))
line++; line++;
if (isempty(line + 1) || isempty(value)) if (isempty(line + 1))
return log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL), return log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL),
"Empty %s in \"%s=%s\", ignoring", "Empty key in \"%s=%s\", ignoring.",
isempty(line + 1) ? "key" : "value",
line, value); line, value);
STRV_FOREACH(entry, match_list) STRV_FOREACH(entry, match_list)
@ -494,7 +486,7 @@ static int import_file(struct trie *trie, const char *filename, uint16_t file_pr
if (r == 0) if (r == 0)
break; break;
++line_number; line_number ++;
/* comment line */ /* comment line */
if (line[0] == '#') if (line[0] == '#')
@ -518,7 +510,7 @@ static int import_file(struct trie *trie, const char *filename, uint16_t file_pr
if (line[0] == ' ') { if (line[0] == ' ') {
r = log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL), r = log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL),
"Match expected but got indented property \"%s\", ignoring line", line); "Match expected but got indented property \"%s\", ignoring line.", line);
break; break;
} }
@ -534,7 +526,7 @@ static int import_file(struct trie *trie, const char *filename, uint16_t file_pr
case HW_MATCH: case HW_MATCH:
if (len == 0) { if (len == 0) {
r = log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL), r = log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL),
"Property expected, ignoring record with no properties"); "Property expected, ignoring record with no properties.");
state = HW_NONE; state = HW_NONE;
match_list = strv_free(match_list); match_list = strv_free(match_list);
break; break;
@ -566,7 +558,7 @@ static int import_file(struct trie *trie, const char *filename, uint16_t file_pr
if (line[0] != ' ') { if (line[0] != ' ') {
r = log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL), r = log_syntax(NULL, LOG_WARNING, filename, line_number, SYNTHETIC_ERRNO(EINVAL),
"Property or empty line expected, got \"%s\", ignoring record", line); "Property or empty line expected, got \"%s\", ignoring record.", line);
state = HW_NONE; state = HW_NONE;
match_list = strv_free(match_list); match_list = strv_free(match_list);
break; break;
@ -581,7 +573,7 @@ static int import_file(struct trie *trie, const char *filename, uint16_t file_pr
if (state == HW_MATCH) if (state == HW_MATCH)
log_syntax(NULL, LOG_WARNING, filename, line_number, 0, log_syntax(NULL, LOG_WARNING, filename, line_number, 0,
"Property expected, ignoring record with no properties"); "Property expected, ignoring record with no properties.");
return r; return r;
} }

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */ /* SPDX-License-Identifier: LGPL-2.1+ */
#include <sched.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <unistd.h> #include <unistd.h>
@ -258,6 +259,16 @@ static void test_path_is_mount_point(void) {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG); test_setup_logging(LOG_DEBUG);
/* let's move into our own mount namespace with all propagation from the host turned off, so that
* /proc/self/mountinfo is static and constant for the whole time our test runs. */
if (unshare(CLONE_NEWNS) < 0) {
if (!ERRNO_IS_PRIVILEGE(errno))
return log_error_errno(errno, "Failed to detach mount namespace: %m");
log_notice("Lacking privilege to create separate mount namespace, proceeding in originating mount namespace.");
} else
assert_se(mount(NULL, "/", NULL, MS_PRIVATE | MS_REC, NULL) >= 0);
test_mount_propagation_flags("shared", 0, MS_SHARED); test_mount_propagation_flags("shared", 0, MS_SHARED);
test_mount_propagation_flags("slave", 0, MS_SLAVE); test_mount_propagation_flags("slave", 0, MS_SLAVE);
test_mount_propagation_flags("private", 0, MS_PRIVATE); test_mount_propagation_flags("private", 0, MS_PRIVATE);