1
0
mirror of https://github.com/systemd/systemd synced 2025-12-24 18:04:45 +01:00

Compare commits

..

30 Commits

Author SHA1 Message Date
Frantisek Sumsal
44dcb318cc
Merge pull request #15842 from evverx/cifuzz
cifuzz: protect forks from CIFuzz
2020-05-19 10:30:32 +02:00
Norbert Lange
cdf7ad38b6 allow removal of initrd services 2020-05-19 10:19:18 +02:00
Zbigniew Jędrzejewski-Szmek
5e375a1ef2
Merge pull request #15794 from poettering/pam-sudo-fixes-part2
pam_systemd/pam_systemd_home: fix caching
2020-05-19 10:09:14 +02:00
Lennart Poettering
201fa8f256
Merge pull request #15166 from ssahani/networkctl-ipvlan
networkctl: Add support to display ipvlan
2020-05-19 09:29:45 +02:00
Lennart Poettering
c5dc0a298e homed: use right config section in example config
We really should get this right, otherwise it's a pretty useless vendor
default example configuration file.

Follow-up for: c76dd733afe04b36cdac16322a07201c5793f2df
2020-05-19 09:26:49 +02:00
Lennart Poettering
619720ba0a
Merge pull request #15810 from poettering/override-first-boot
core: allow overriding needs-update/first-boot/system clock via kernel cmdline
2020-05-19 08:45:59 +02:00
Lennart Poettering
01bcea4999 dhcp6: slightly improve log message
Let's clarify that we proceed anyway.

Prompted-by: #15830
2020-05-19 08:25:43 +02:00
Evgeny Vereshchagin
e2cf880e68 README: add a CIFuzz badge
Just a follow-up to https://github.com/systemd/systemd/pull/15760
2020-05-19 08:12:23 +02:00
Evgeny Vereshchagin
82d7a25ee6 cifuzz: protect forks from CIFuzz
CIFuzz isn't compatible with forks: https://github.com/google/oss-fuzz/issues/3731
2020-05-19 08:12:07 +02:00
Vladyslav Tronko
bc48b25afd journal: fix dropping first record during upload to remote journal 2020-05-19 07:58:59 +02:00
Zbigniew Jędrzejewski-Szmek
abc72137d1
Merge pull request #15838 from poettering/hostnamed-instant-part2
more hostnamed fixes, split out of #15624
2020-05-19 07:54:47 +02:00
Lennart Poettering
cfb9433de4 hostnamed: call our destructor _destroy(), not _clear() 2020-05-18 21:12:37 +02:00
Lennart Poettering
5704cd733c hostnamed: don't cache system UUID
There's no point in caching this. Let's always get this directly from
sysfs, so that we can never get out-of-date data here (after all this is
going to be cheap, and people might overmount it or so)
2020-05-18 21:11:50 +02:00
Lennart Poettering
72f48cd3e3 hostnamed: don't cache uname() data
Let's not cache the uname(), it's very cheap to get it, and just means
we might get out of sync with what is current. After all, the data might
change IRL, due to setarch and stuff.
2020-05-18 21:11:50 +02:00
Lennart Poettering
c6526b8d66 update TODO 2020-05-18 20:20:50 +02:00
Lennart Poettering
34293dfafd core: allow overriding the system hostname with systemd.hostname= on the kernel command line 2020-05-18 20:20:50 +02:00
Lennart Poettering
3753325bef main: add a kernel command line option for setting the system clock early during boot 2020-05-18 20:20:50 +02:00
Lennart Poettering
814872e925 condition: introduce systemd.condition-first-boot= kernel command line switch
Much like systemd.condition-needs-update= this new switch allows
overriding of a unit file condition, but this time its
ConditionFirstBoot=.

Usecase is also primarily debugging, but could be useful for other
schemes too.
2020-05-18 20:20:50 +02:00
Lennart Poettering
5439d8212c condition: debug log if F_OK check on /run/systemd/first-boot fails unexpectedly 2020-05-18 20:20:50 +02:00
Lennart Poettering
ce0f7f5546 condition: reverse if check to lower indentation level
No change in behaviour. Let's just prefer early exit over deeper
indentation.
2020-05-18 20:20:22 +02:00
Lennart Poettering
f8b4ae29c7 condition: allow overriding of ConditionNeedsUpdate= on the kernel command line
This should be useful for addressing #15724.
2020-05-18 20:17:57 +02:00
Lennart Poettering
3931056767 proc-cmdline: add some explanatory comments 2020-05-18 20:17:57 +02:00
Lennart Poettering
b2d1ad757c condition: when reading /etc/ modification timestamp, let's actualy compare it as-is
Previously, we'd only compare the nsec component of it, which sounds
needlessly fragile. Let's instead compare the timestamp as it is.
2020-05-18 20:17:57 +02:00
Lennart Poettering
f33cd69b5c condition: downgrade a few log messages to debug
Condition checks shouldn't log loudly, since they run all the time.
Let's make things debuggable, by keeping the messages in LOG_DEBUG in,
but don't make more noise than necessary.
2020-05-18 20:17:57 +02:00
Lennart Poettering
df1f5dc1d9 condition: add debug log messages on unexpected errors 2020-05-18 20:17:57 +02:00
Lennart Poettering
841c0987f7 condition: check if path is absolute first
We should do this check first since it is done on the string itself
without any conditioning of system state otherwise. It is a weird to do
this test only if /etc is read-only.
2020-05-18 19:55:56 +02:00
Susant Sahani
851ef1ed56 networkctl: Add support to display ipvlan
```
build/networkctl status myipvlan1                                                                                                                                                        ─╯
● 26: myipvlan1
             Link File: /usr/lib/systemd/network/99-default.link
          Network File: n/a
                  Type: ether
                 State: off (unmanaged)
                Driver: ipvlan
            HW Address: 4e:c5:88:28:c1:c0
                   MTU: 1500 (min: 68, max: 65535)
                 QDisc: noop
                  Mode: L2 (bridge)
  Queue Length (Tx/Rx): 1/1

```
2020-05-18 19:07:04 +02:00
Susant Sahani
35072050e6 network: Introduce ipvlan util
Move ipvlan common to shared
2020-05-17 05:34:19 +02:00
Lennart Poettering
6c8428bb8b pam_systemd_home: also store acquirement fd per user
We might pin a home through authentication and a different one through a
session, all from the same PAM context, like sudo does. Hence also store
the referencing fd keyed by the user name.
2020-05-12 17:38:32 +02:00
Lennart Poettering
dbe7fff476 pam_systemd/pam_systemd_home: rework how we cache user records
Since acquiring user records involves plenty of IPC we try to cache user
records in the PAM context between our various hooks. Previously we'd
just cache whatever we acquired, and use it from the on, forever until
the context is destroyed.

This is problematic however, since some programs (notably sudo) use the
same PAM context for multiple different operations. Specifically, sudo
first authenticates the originating user before creating a session for
the destination user, all with the same PAM context. Thankfully, there
was a safety check for this case in place that re-validated that the
cached user record actually matched our current idea of the user to
operate on, but this just meant the hook would fail entirely.

Let's rework this: let's key the cache by the user name, so that we do
not confused by the changing of the user name during the context's
lifecycle and always, strictly use the cached user record of the user we
operate on.

Essentially this just means we now include the user name in the PAM data
field.

Secondly, this gets rid of the extra PAM data field that indicates
whether a user record is from homed or something else. To simplify
things we instead just cache the user record twice: once for consumption
by pam_systemd_home (which only wants homed records) and once shared by
pam_systemd and pam_systemd_home (and whoever else wants it). The cache
entries simply have different field names.
2020-05-12 17:38:32 +02:00
26 changed files with 502 additions and 244 deletions

View File

@ -18,6 +18,7 @@ on:
jobs: jobs:
Fuzzing: Fuzzing:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.repository == 'systemd/systemd'
steps: steps:
- name: Build Fuzzers - name: Build Fuzzers
id: build id: build

View File

@ -8,6 +8,7 @@ System and Service Manager
[![Coverity Scan Status](https://scan.coverity.com/projects/350/badge.svg)](https://scan.coverity.com/projects/350)<br/> [![Coverity Scan Status](https://scan.coverity.com/projects/350/badge.svg)](https://scan.coverity.com/projects/350)<br/>
[![Fuzzit Status](https://app.fuzzit.dev/badge?org_id=systemd&branch=master)](https://app.fuzzit.dev/orgs/systemd/dashboard)<br/> [![Fuzzit Status](https://app.fuzzit.dev/badge?org_id=systemd&branch=master)](https://app.fuzzit.dev/orgs/systemd/dashboard)<br/>
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/systemd.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#systemd)<br/> [![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/systemd.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#systemd)<br/>
[![CIFuzz](https://github.com/systemd/systemd/workflows/CIFuzz/badge.svg)](https://github.com/systemd/systemd/actions)<br/>
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1369/badge)](https://bestpractices.coreinfrastructure.org/projects/1369)<br/> [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1369/badge)](https://bestpractices.coreinfrastructure.org/projects/1369)<br/>
[![Travis CI Build Status](https://travis-ci.org/systemd/systemd.svg?branch=master)](https://travis-ci.org/systemd/systemd)<br/> [![Travis CI Build Status](https://travis-ci.org/systemd/systemd.svg?branch=master)](https://travis-ci.org/systemd/systemd)<br/>
[![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/systemd/systemd.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/systemd/systemd/context:cpp)<br/> [![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/systemd/systemd.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/systemd/systemd/context:cpp)<br/>

3
TODO
View File

@ -252,8 +252,7 @@ Features:
that are linked to these places instead of copied. After all they are that are linked to these places instead of copied. After all they are
constant vendor data. constant vendor data.
* maybe add kernel cmdline params: 1) to force first-boot mode + 2) to force * maybe add kernel cmdline params: to force random seed crediting
random seed crediting
* nspawn: on cgroupsv1 issue cgroup empty handler process based on host events, * nspawn: on cgroupsv1 issue cgroup empty handler process based on host events,
so that we make cgroup agent logic safe so that we make cgroup agent logic safe

View File

@ -433,8 +433,47 @@
<listitem><para>Takes a boolean argument, defaults to on. If off, <listitem><para>Takes a boolean argument, defaults to on. If off,
<citerefentry><refentrytitle>systemd-firstboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> <citerefentry><refentrytitle>systemd-firstboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
will not query the user for basic system settings, even if the system boots up for the first time and the will not query the user for basic system settings, even if the system boots up for the first time and
relevant settings are not initialized yet.</para></listitem> the relevant settings are not initialized yet. Not to be confused with
<varname>systemd.condition-first-boot=</varname> (see below), which overrides the result of the
<varname>ConditionFirstBoot=</varname> unit file condition, and thus controls more than just
<filename>systemd-firstboot.service</filename> behaviour.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.condition-needs-update=</varname></term>
<listitem><para>Takes a boolean argument. If specified, overrides the result of
<varname>ConditionNeedsUpdate=</varname> unit condition checks. See
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.condition-first-boot=</varname></term>
<listitem><para>Takes a boolean argument. If specified, overrides the result of
<varname>ConditionFirstBoot=</varname> unit condition checks. See
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details. Not to be confused with <varname>systemd.firstboot=</varname> which only controls behaviour
of the <filename>systemd-firstboot.service</filename> system service but has no effect on the
condition check (see above).</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.clock-usec=</varname></term>
<listitem><para>Takes a decimal, numeric timestamp in µs since January 1st 1970, 00:00am, to set the
system clock to. The system time is set to the specified timestamp early during
boot. It is not propagated to the hardware clock (RTC).</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.hostname=</varname></term>
<listitem><para>Accepts a hostname to set during early boot. If specified takes precedence over what
is set in <filename>/etc/hostname</filename>. Note that this does not bar later runtime changes to
the hostname, it simply controls the initial hostname set during early boot.</para></listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -58,6 +58,10 @@
<citerefentry project='man-pages'><refentrytitle>touch</refentrytitle><manvolnum>1</manvolnum></citerefentry> <citerefentry project='man-pages'><refentrytitle>touch</refentrytitle><manvolnum>1</manvolnum></citerefentry>
on it.</para> on it.</para>
<para>Note that if the <varname>systemd.condition-needs-update=</varname> kernel command line option is
used it overrides the <varname>ConditionNeedsUpdate=</varname> unit condition checks. In that case
<filename>systemd-update-done.service</filename> will not reset the condition state until a follow-up
reboot where the kernel switch is not specified anymore.</para>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -1294,6 +1294,13 @@
<citerefentry><refentrytitle>systemd-update-done.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-update-done.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
to make sure they run before the stamp file's modification time gets reset indicating a completed to make sure they run before the stamp file's modification time gets reset indicating a completed
update.</para> update.</para>
<para>If the <varname>systemd.condition-needs-update=</varname> option is specified on the kernel
command line (taking a boolean), it will override the result of this condition check, taking
precedence over any file modification time checks. If it is used
<filename>systemd-update-done.service</filename> will not have immediate effect on any following
<varname>ConditionNeedsUpdate=</varname> checks, until the system is rebooted where the kernel
command line option is not specified anymore.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -1305,6 +1312,10 @@
(specifically: an <filename>/etc</filename> with no <filename>/etc/machine-id</filename>). This may (specifically: an <filename>/etc</filename> with no <filename>/etc/machine-id</filename>). This may
be used to populate <filename>/etc</filename> on the first boot after factory reset, or when a new be used to populate <filename>/etc</filename> on the first boot after factory reset, or when a new
system instance boots up for the first time.</para> system instance boots up for the first time.</para>
<para>If the <varname>systemd.condition-first-boot=</varname> option is specified on the kernel
command line (taking a boolean), it will override the result of this condition check, taking
precedence over <filename>/etc/machine-id</filename> existence checks.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -90,6 +90,10 @@ sysvrcnd_path = get_option('sysvrcnd-path')
conf.set10('HAVE_SYSV_COMPAT', sysvinit_path != '' and sysvrcnd_path != '', conf.set10('HAVE_SYSV_COMPAT', sysvinit_path != '' and sysvrcnd_path != '',
description : 'SysV init scripts and rcN.d links are supported') description : 'SysV init scripts and rcN.d links are supported')
if get_option('hibernate') and not get_option('initrd')
error('hibernate depends on initrd')
endif
conf.set10('BUMP_PROC_SYS_FS_FILE_MAX', get_option('bump-proc-sys-fs-file-max')) conf.set10('BUMP_PROC_SYS_FS_FILE_MAX', get_option('bump-proc-sys-fs-file-max'))
conf.set10('BUMP_PROC_SYS_FS_NR_OPEN', get_option('bump-proc-sys-fs-nr-open')) conf.set10('BUMP_PROC_SYS_FS_NR_OPEN', get_option('bump-proc-sys-fs-nr-open'))
conf.set('HIGH_RLIMIT_NOFILE', 512*1024) conf.set('HIGH_RLIMIT_NOFILE', 512*1024)
@ -1419,6 +1423,7 @@ foreach term : ['utmp',
'smack', 'smack',
'gshadow', 'gshadow',
'idn', 'idn',
'initrd',
'nss-myhostname', 'nss-myhostname',
'nss-systemd'] 'nss-systemd']
have = get_option(term) have = get_option(term)
@ -2766,7 +2771,7 @@ executable(
include_directories : includes, include_directories : includes,
link_with : [libshared], link_with : [libshared],
install_rpath : rootlibexecdir, install_rpath : rootlibexecdir,
install : true, install : conf.get('ENABLE_INITRD') == 1,
install_dir : rootlibexecdir) install_dir : rootlibexecdir)
executable( executable(
@ -3539,6 +3544,7 @@ foreach tuple : [
['openssl'], ['openssl'],
['libcurl'], ['libcurl'],
['idn'], ['idn'],
['initrd'],
['libidn2'], ['libidn2'],
['libidn'], ['libidn'],
['libiptc'], ['libiptc'],

View File

@ -35,6 +35,8 @@ option('telinit-path', type : 'string', value : '/lib/sysvinit/telinit',
description : 'path to telinit') description : 'path to telinit')
option('rc-local', type : 'string', option('rc-local', type : 'string',
value : '/etc/rc.local') value : '/etc/rc.local')
option('initrd', type: 'boolean',
description : 'install services for use when running systemd in initrd')
option('quotaon-path', type : 'string', description : 'path to quotaon') option('quotaon-path', type : 'string', description : 'path to quotaon')
option('quotacheck-path', type : 'string', description : 'path to quotacheck') option('quotacheck-path', type : 'string', description : 'path to quotacheck')

View File

@ -268,17 +268,17 @@ int proc_cmdline_get_bool(const char *key, bool *ret) {
r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &v); r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &v);
if (r < 0) if (r < 0)
return r; return r;
if (r == 0) { if (r == 0) { /* key not specified at all */
*ret = false; *ret = false;
return 0; return 0;
} }
if (v) { /* parameter passed */ if (v) { /* key with parameter passed */
r = parse_boolean(v); r = parse_boolean(v);
if (r < 0) if (r < 0)
return r; return r;
*ret = r; *ret = r;
} else /* no parameter passed */ } else /* key without parameter passed */
*ret = true; *ret = true;
return 1; return 1;

View File

@ -6,9 +6,9 @@
#include "log.h" #include "log.h"
typedef enum ProcCmdlineFlags { typedef enum ProcCmdlineFlags {
PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0, PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0, /* automatically strip "rd." prefix if it is set (and we are in the initrd, since otherwise we'd not consider it anyway) */
PROC_CMDLINE_VALUE_OPTIONAL = 1 << 1, PROC_CMDLINE_VALUE_OPTIONAL = 1 << 1, /* the value is optional (for boolean switches that can omit the value) */
PROC_CMDLINE_RD_STRICT = 1 << 2, PROC_CMDLINE_RD_STRICT = 1 << 2, /* ignore this in the initrd */
} ProcCmdlineFlags; } ProcCmdlineFlags;
typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data); typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data);

View File

@ -10,29 +10,41 @@
#include "hostname-util.h" #include "hostname-util.h"
#include "log.h" #include "log.h"
#include "macro.h" #include "macro.h"
#include "proc-cmdline.h"
#include "string-util.h" #include "string-util.h"
#include "util.h" #include "util.h"
int hostname_setup(void) { int hostname_setup(void) {
_cleanup_free_ char *b = NULL; _cleanup_free_ char *b = NULL;
const char *hn = NULL;
bool enoent = false; bool enoent = false;
const char *hn;
int r; int r;
r = proc_cmdline_get_key("systemd.hostname", 0, &b);
if (r < 0)
log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m");
else if (r > 0) {
if (hostname_is_valid(b, true))
hn = b;
else {
log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b);
b = mfree(b);
}
}
if (!hn) {
r = read_etc_hostname(NULL, &b); r = read_etc_hostname(NULL, &b);
if (r < 0) { if (r < 0) {
if (r == -ENOENT) if (r == -ENOENT)
enoent = true; enoent = true;
else else
log_warning_errno(r, "Failed to read configured hostname: %m"); log_warning_errno(r, "Failed to read configured hostname: %m");
hn = NULL;
} else } else
hn = b; hn = b;
}
if (isempty(hn)) { if (isempty(hn)) {
/* Don't override the hostname if it is already set /* Don't override the hostname if it is already set and not explicitly configured */
* and not explicitly configured */
if (hostname_is_set()) if (hostname_is_set())
return 0; return 0;

View File

@ -146,6 +146,7 @@ static EmergencyAction arg_cad_burst_action;
static OOMPolicy arg_default_oom_policy; static OOMPolicy arg_default_oom_policy;
static CPUSet arg_cpu_affinity; static CPUSet arg_cpu_affinity;
static NUMAPolicy arg_numa_policy; static NUMAPolicy arg_numa_policy;
static usec_t arg_clock_usec;
/* A copy of the original environment block */ /* A copy of the original environment block */
static char **saved_env = NULL; static char **saved_env = NULL;
@ -491,6 +492,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
(void) parse_path_argument_and_warn(value, false, &arg_watchdog_device); (void) parse_path_argument_and_warn(value, false, &arg_watchdog_device);
} else if (proc_cmdline_key_streq(key, "systemd.clock_usec")) {
if (proc_cmdline_value_missing(key, value))
return 0;
r = safe_atou64(value, &arg_clock_usec);
if (r < 0)
log_warning_errno(r, "Failed to parse systemd.clock_usec= argument, ignoring: %s", value);
} else if (streq(key, "quiet") && !value) { } else if (streq(key, "quiet") && !value) {
if (arg_show_status == _SHOW_STATUS_INVALID) if (arg_show_status == _SHOW_STATUS_INVALID)
@ -1504,6 +1514,9 @@ static int become_shutdown(
static void initialize_clock(void) { static void initialize_clock(void) {
int r; int r;
/* This is called very early on, before we parse the kernel command line or otherwise figure out why
* we are running, but only once. */
if (clock_is_localtime(NULL) > 0) { if (clock_is_localtime(NULL) > 0) {
int min; int min;
@ -1542,6 +1555,25 @@ static void initialize_clock(void) {
log_info("System time before build time, advancing clock."); log_info("System time before build time, advancing clock.");
} }
static void apply_clock_update(void) {
struct timespec ts;
/* This is called later than initialize_clock(), i.e. after we parsed configuration files/kernel
* command line and such. */
if (arg_clock_usec == 0)
return;
if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, arg_clock_usec)) < 0)
log_error_errno(errno, "Failed to set system clock to time specified on kernel command line: %m");
else {
char buf[FORMAT_TIMESTAMP_MAX];
log_info("Set system clock to %s, as specified on the kernel command line.",
format_timestamp(buf, sizeof(buf), arg_clock_usec));
}
}
static void initialize_coredump(bool skip_setup) { static void initialize_coredump(bool skip_setup) {
#if ENABLE_COREDUMP #if ENABLE_COREDUMP
if (getpid_cached() != 1) if (getpid_cached() != 1)
@ -2658,6 +2690,8 @@ int main(int argc, char *argv[]) {
assert_se(chdir("/") == 0); assert_se(chdir("/") == 0);
if (arg_action == ACTION_RUN) { if (arg_action == ACTION_RUN) {
/* Apply the systemd.clock_usec= kernel command line switch */
apply_clock_update();
/* A core pattern might have been specified via the cmdline. */ /* A core pattern might have been specified via the cmdline. */
initialize_core_pattern(skip_setup); initialize_core_pattern(skip_setup);

View File

@ -11,6 +11,6 @@
# #
# See homed.conf(5) for details # See homed.conf(5) for details
[Resolve] [Home]
#DefaultStorage= #DefaultStorage=
#DefaultFileSystemType=ext4 #DefaultFileSystemType=ext4

View File

@ -18,11 +18,6 @@
#include "user-record.h" #include "user-record.h"
#include "user-util.h" #include "user-util.h"
/* Used for the "systemd-user-record-is-homed" PAM data field, to indicate whether we know whether this user
* record is managed by homed or by something else. */
#define USER_RECORD_IS_HOMED INT_TO_PTR(1)
#define USER_RECORD_IS_OTHER INT_TO_PTR(2)
static int parse_argv( static int parse_argv(
pam_handle_t *handle, pam_handle_t *handle,
int argc, const char **argv, int argc, const char **argv,
@ -67,18 +62,20 @@ static int parse_argv(
static int acquire_user_record( static int acquire_user_record(
pam_handle_t *handle, pam_handle_t *handle,
const char *username,
UserRecord **ret_record) { UserRecord **ret_record) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL; _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_(user_record_unrefp) UserRecord *ur = NULL; _cleanup_(user_record_unrefp) UserRecord *ur = NULL;
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
const char *username = NULL, *json = NULL; _cleanup_free_ char *homed_field = NULL;
const void *b = NULL; const char *json = NULL;
int r; int r;
assert(handle); assert(handle);
if (!username) {
r = pam_get_user(handle, &username, NULL); r = pam_get_user(handle, &username, NULL);
if (r != PAM_SUCCESS) { if (r != PAM_SUCCESS) {
pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r)); pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
@ -89,37 +86,37 @@ static int acquire_user_record(
pam_syslog(handle, LOG_ERR, "User name not set."); pam_syslog(handle, LOG_ERR, "User name not set.");
return PAM_SERVICE_ERR; return PAM_SERVICE_ERR;
} }
}
/* Let's bypass all IPC complexity for the two user names we know for sure we don't manage, and for /* Let's bypass all IPC complexity for the two user names we know for sure we don't manage, and for
* user names we don't consider valid. */ * user names we don't consider valid. */
if (STR_IN_SET(username, "root", NOBODY_USER_NAME) || !valid_user_group_name(username, 0)) if (STR_IN_SET(username, "root", NOBODY_USER_NAME) || !valid_user_group_name(username, 0))
return PAM_USER_UNKNOWN; return PAM_USER_UNKNOWN;
/* Let's check if a previous run determined that this user is not managed by homed. If so, let's exit early */ /* We cache the user record in the PAM context. We use a field name that includes the username, since
r = pam_get_data(handle, "systemd-user-record-is-homed", &b); * clients might change the user name associated with a PAM context underneath us. Notably, 'sudo'
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) { * creates a single PAM context and first authenticates it with the user set to the originating user,
/* Failure */ * then updates the user for the destination user and issues the session stack with the same PAM
pam_syslog(handle, LOG_ERR, "Failed to get PAM user-record-is-homed flag: %s", pam_strerror(handle, r)); * context. We thus must be prepared that the user record changes between calls and we keep any
return r; * caching separate. */
} else if (b == NULL) homed_field = strjoin("systemd-home-user-record-", username);
/* Nothing cached yet, need to acquire fresh */ if (!homed_field)
json = NULL; return pam_log_oom(handle);
else if (b != USER_RECORD_IS_HOMED)
/* Definitely not a homed record */ /* Let's use the cache, so that we can share it between the session and the authentication hooks */
return PAM_USER_UNKNOWN; r = pam_get_data(handle, homed_field, (const void**) &json);
else {
/* It's a homed record, let's use the cache, so that we can share it between the session and
* the authentication hooks */
r = pam_get_data(handle, "systemd-user-record", (const void**) &json);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) { if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r)); pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r));
return r; return r;
} }
} if (r == PAM_SUCCESS && json) {
/* We determined earlier that this is not a homed user? Then exit early. (We use -1 as
if (!json) { * negative cache indicator) */
if (json == (void*) -1)
return PAM_USER_UNKNOWN;
} else {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *json_copy = NULL; _cleanup_free_ char *generic_field = NULL, *json_copy = NULL;
r = pam_acquire_bus_connection(handle, &bus); r = pam_acquire_bus_connection(handle, &bus);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
@ -146,23 +143,38 @@ static int acquire_user_record(
if (r < 0) if (r < 0)
return pam_bus_log_parse_error(handle, r); return pam_bus_log_parse_error(handle, r);
/* First copy: for the homed-specific data field, i.e. where we know the user record is from
* homed */
json_copy = strdup(json); json_copy = strdup(json);
if (!json_copy) if (!json_copy)
return pam_log_oom(handle); return pam_log_oom(handle);
r = pam_set_data(handle, "systemd-user-record", json_copy, pam_cleanup_free); r = pam_set_data(handle, homed_field, json_copy, pam_cleanup_free);
if (r != PAM_SUCCESS) { if (r != PAM_SUCCESS) {
pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data: %s", pam_strerror(handle, r)); pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s': %s",
homed_field, pam_strerror(handle, r));
return r;
}
/* Take a second copy: for the generic data field, the one which we share with
* pam_systemd. While we insist on only reusing homed records, pam_systemd is fine with homed
* and non-homed user records. */
json_copy = strdup(json);
if (!json_copy)
return pam_log_oom(handle);
generic_field = strjoin("systemd-user-record-", username);
if (!generic_field)
return pam_log_oom(handle);
r = pam_set_data(handle, generic_field, json_copy, pam_cleanup_free);
if (r != PAM_SUCCESS) {
pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s': %s",
homed_field, pam_strerror(handle, r));
return r; return r;
} }
TAKE_PTR(json_copy); TAKE_PTR(json_copy);
r = pam_set_data(handle, "systemd-user-record-is-homed", USER_RECORD_IS_HOMED, NULL);
if (r != PAM_SUCCESS) {
pam_syslog(handle, LOG_ERR, "Failed to set PAM user record is homed flag: %s", pam_strerror(handle, r));
return r;
}
} }
r = json_parse(json, JSON_PARSE_SENSITIVE, &v, NULL, NULL); r = json_parse(json, JSON_PARSE_SENSITIVE, &v, NULL, NULL);
@ -181,6 +193,7 @@ static int acquire_user_record(
return PAM_SERVICE_ERR; return PAM_SERVICE_ERR;
} }
/* Safety check if cached record actually matches what we are looking for */
if (!streq_ptr(username, ur->user_name)) { if (!streq_ptr(username, ur->user_name)) {
pam_syslog(handle, LOG_ERR, "Acquired user record does not match user name."); pam_syslog(handle, LOG_ERR, "Acquired user record does not match user name.");
return PAM_SERVICE_ERR; return PAM_SERVICE_ERR;
@ -193,23 +206,36 @@ static int acquire_user_record(
user_unknown: user_unknown:
/* Cache this, so that we don't check again */ /* Cache this, so that we don't check again */
r = pam_set_data(handle, "systemd-user-record-is-homed", USER_RECORD_IS_OTHER, NULL); r = pam_set_data(handle, homed_field, (void*) -1, NULL);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
pam_syslog(handle, LOG_ERR, "Failed to set PAM user-record-is-homed flag, ignoring: %s", pam_strerror(handle, r)); pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s' to invalid, ignoring: %s",
homed_field, pam_strerror(handle, r));
return PAM_USER_UNKNOWN; return PAM_USER_UNKNOWN;
} }
static int release_user_record(pam_handle_t *handle) { static int release_user_record(pam_handle_t *handle, const char *username) {
_cleanup_free_ char *homed_field = NULL, *generic_field = NULL;
int r, k; int r, k;
r = pam_set_data(handle, "systemd-user-record", NULL, NULL); assert(handle);
if (r != PAM_SUCCESS) assert(username);
pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data: %s", pam_strerror(handle, r));
k = pam_set_data(handle, "systemd-user-record-is-homed", NULL, NULL); homed_field = strjoin("systemd-home-user-record-", username);
if (!homed_field)
return pam_log_oom(handle);
r = pam_set_data(handle, homed_field, NULL, NULL);
if (r != PAM_SUCCESS)
pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data '%s': %s", homed_field, pam_strerror(handle, r));
generic_field = strjoin("systemd-user-record-", username);
if (!generic_field)
return pam_log_oom(handle);
k = pam_set_data(handle, generic_field, NULL, NULL);
if (k != PAM_SUCCESS) if (k != PAM_SUCCESS)
pam_syslog(handle, LOG_ERR, "Failed to release PAM user-record-is-homed flag: %s", pam_strerror(handle, k)); pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data '%s': %s", generic_field, pam_strerror(handle, k));
return IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA) ? k : r; return IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA) ? k : r;
} }
@ -395,7 +421,9 @@ static int acquire_home(
bool do_auth = please_authenticate, home_not_active = false, home_locked = false; bool do_auth = please_authenticate, home_not_active = false, home_locked = false;
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
_cleanup_close_ int acquired_fd = -1; _cleanup_close_ int acquired_fd = -1;
_cleanup_free_ char *fd_field = NULL;
const void *home_fd_ptr = NULL; const void *home_fd_ptr = NULL;
const char *username = NULL;
unsigned n_attempts = 0; unsigned n_attempts = 0;
int r; int r;
@ -409,8 +437,27 @@ static int acquire_home(
* authenticates, while the other PAM hooks unset it so that they can a ref of their own without * authenticates, while the other PAM hooks unset it so that they can a ref of their own without
* authentication if possible, but with authentication if necessary. */ * authentication if possible, but with authentication if necessary. */
r = pam_get_user(handle, &username, NULL);
if (r != PAM_SUCCESS) {
pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
return r;
}
if (isempty(username)) {
pam_syslog(handle, LOG_ERR, "User name not set.");
return PAM_SERVICE_ERR;
}
/* If we already have acquired the fd, let's shortcut this */ /* If we already have acquired the fd, let's shortcut this */
r = pam_get_data(handle, "systemd-home-fd", &home_fd_ptr); fd_field = strjoin("systemd-home-fd-", username);
if (!fd_field)
return pam_log_oom(handle);
r = pam_get_data(handle, fd_field, &home_fd_ptr);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
pam_syslog(handle, LOG_ERR, "Failed to retrieve PAM home reference fd: %s", pam_strerror(handle, r));
return r;
}
if (r == PAM_SUCCESS && PTR_TO_FD(home_fd_ptr) >= 0) if (r == PAM_SUCCESS && PTR_TO_FD(home_fd_ptr) >= 0)
return PAM_SUCCESS; return PAM_SUCCESS;
@ -418,7 +465,7 @@ static int acquire_home(
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
r = acquire_user_record(handle, &ur); r = acquire_user_record(handle, username, &ur);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
@ -534,7 +581,7 @@ static int acquire_home(
do_auth = true; do_auth = true;
} }
r = pam_set_data(handle, "systemd-home-fd", FD_TO_PTR(acquired_fd), cleanup_home_fd); r = pam_set_data(handle, fd_field, FD_TO_PTR(acquired_fd), cleanup_home_fd);
if (r < 0) { if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to set PAM bus data: %s", pam_strerror(handle, r)); pam_syslog(handle, LOG_ERR, "Failed to set PAM bus data: %s", pam_strerror(handle, r));
return r; return r;
@ -545,7 +592,7 @@ static int acquire_home(
/* We likely just activated the home directory, let's flush out the user record, since a /* We likely just activated the home directory, let's flush out the user record, since a
* newer embedded user record might have been acquired from the activation. */ * newer embedded user record might have been acquired from the activation. */
r = release_user_record(handle); r = release_user_record(handle, ur->user_name);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return r; return r;
} }
@ -555,15 +602,27 @@ static int acquire_home(
return PAM_SUCCESS; return PAM_SUCCESS;
} }
static int release_home_fd(pam_handle_t *handle) { static int release_home_fd(pam_handle_t *handle, const char *username) {
_cleanup_free_ char *fd_field = NULL;
const void *home_fd_ptr = NULL; const void *home_fd_ptr = NULL;
int r; int r;
r = pam_get_data(handle, "systemd-home-fd", &home_fd_ptr); assert(handle);
if (r == PAM_NO_MODULE_DATA || PTR_TO_FD(home_fd_ptr) < 0) assert(username);
return PAM_NO_MODULE_DATA;
r = pam_set_data(handle, "systemd-home-fd", NULL, NULL); fd_field = strjoin("systemd-home-fd-", username);
if (!fd_field)
return pam_log_oom(handle);
r = pam_get_data(handle, fd_field, &home_fd_ptr);
if (r == PAM_NO_MODULE_DATA || (r == PAM_SUCCESS && PTR_TO_FD(home_fd_ptr) < 0))
return PAM_NO_MODULE_DATA;
if (r != PAM_SUCCESS) {
pam_syslog(handle, LOG_ERR, "Failed to retrieve PAM home reference fd: %s", pam_strerror(handle, r));
return r;
}
r = pam_set_data(handle, fd_field, NULL, NULL);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
pam_syslog(handle, LOG_ERR, "Failed to release PAM home reference fd: %s", pam_strerror(handle, r)); pam_syslog(handle, LOG_ERR, "Failed to release PAM home reference fd: %s", pam_strerror(handle, r));
@ -650,20 +709,25 @@ _public_ PAM_EXTERN int pam_sm_close_session(
if (debug) if (debug)
pam_syslog(handle, LOG_DEBUG, "pam-systemd-homed session end"); pam_syslog(handle, LOG_DEBUG, "pam-systemd-homed session end");
/* Let's explicitly drop the reference to the homed session, so that the subsequent ReleaseHome()
* call will be able to do its thing. */
r = release_home_fd(handle);
if (r == PAM_NO_MODULE_DATA) /* Nothing to do, we never acquired an fd */
return PAM_SUCCESS;
if (r != PAM_SUCCESS)
return r;
r = pam_get_user(handle, &username, NULL); r = pam_get_user(handle, &username, NULL);
if (r != PAM_SUCCESS) { if (r != PAM_SUCCESS) {
pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r)); pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
return r; return r;
} }
if (isempty(username)) {
pam_syslog(handle, LOG_ERR, "User name not set.");
return PAM_SERVICE_ERR;
}
/* Let's explicitly drop the reference to the homed session, so that the subsequent ReleaseHome()
* call will be able to do its thing. */
r = release_home_fd(handle, username);
if (r == PAM_NO_MODULE_DATA) /* Nothing to do, we never acquired an fd */
return PAM_SUCCESS;
if (r != PAM_SUCCESS)
return r;
r = pam_acquire_bus_connection(handle, &bus); r = pam_acquire_bus_connection(handle, &bus);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
@ -715,7 +779,7 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt(
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
r = acquire_user_record(handle, &ur); r = acquire_user_record(handle, NULL, &ur);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
@ -823,7 +887,7 @@ _public_ PAM_EXTERN int pam_sm_chauthtok(
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
r = acquire_user_record(handle, &ur); r = acquire_user_record(handle, NULL, &ur);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;

View File

@ -43,9 +43,6 @@ enum {
PROP_CHASSIS, PROP_CHASSIS,
PROP_DEPLOYMENT, PROP_DEPLOYMENT,
PROP_LOCATION, PROP_LOCATION,
PROP_KERNEL_NAME,
PROP_KERNEL_RELEASE,
PROP_KERNEL_VERSION,
PROP_OS_PRETTY_NAME, PROP_OS_PRETTY_NAME,
PROP_OS_CPE_NAME, PROP_OS_CPE_NAME,
PROP_HOME_URL, PROP_HOME_URL,
@ -55,8 +52,6 @@ enum {
typedef struct Context { typedef struct Context {
char *data[_PROP_MAX]; char *data[_PROP_MAX];
Hashmap *polkit_registry; Hashmap *polkit_registry;
sd_id128_t uuid;
bool has_uuid;
} Context; } Context;
static void context_reset(Context *c) { static void context_reset(Context *c) {
@ -68,7 +63,7 @@ static void context_reset(Context *c) {
c->data[p] = mfree(c->data[p]); c->data[p] = mfree(c->data[p]);
} }
static void context_clear(Context *c) { static void context_destroy(Context *c) {
assert(c); assert(c);
context_reset(c); context_reset(c);
@ -77,20 +72,11 @@ static void context_clear(Context *c) {
static int context_read_data(Context *c) { static int context_read_data(Context *c) {
int r; int r;
struct utsname u;
assert(c); assert(c);
context_reset(c); context_reset(c);
assert_se(uname(&u) >= 0);
c->data[PROP_KERNEL_NAME] = strdup(u.sysname);
c->data[PROP_KERNEL_RELEASE] = strdup(u.release);
c->data[PROP_KERNEL_VERSION] = strdup(u.version);
if (!c->data[PROP_KERNEL_NAME] || !c->data[PROP_KERNEL_RELEASE] ||
!c->data[PROP_KERNEL_VERSION])
return -ENOMEM;
c->data[PROP_HOSTNAME] = gethostname_malloc(); c->data[PROP_HOSTNAME] = gethostname_malloc();
if (!c->data[PROP_HOSTNAME]) if (!c->data[PROP_HOSTNAME])
return -ENOMEM; return -ENOMEM;
@ -116,17 +102,6 @@ static int context_read_data(Context *c) {
if (r < 0 && r != -ENOENT) if (r < 0 && r != -ENOENT)
return r; return r;
r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &c->uuid);
if (r == -ENOENT)
r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &c->uuid);
if (r < 0)
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to read product UUID, ignoring: %m");
else if (sd_id128_is_null(c->uuid) || sd_id128_is_allf(c->uuid))
log_debug("DMI product UUID " SD_ID128_FORMAT_STR " is all 0x00 or all 0xFF, ignoring.", SD_ID128_FORMAT_VAL(c->uuid));
else
c->has_uuid = true;
return 0; return 0;
} }
@ -411,6 +386,22 @@ static int property_get_chassis(
return sd_bus_message_append(reply, "s", name); return sd_bus_message_append(reply, "s", name);
} }
static int property_get_uname_field(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
struct utsname u;
assert_se(uname(&u) >= 0);
return sd_bus_message_append(reply, "s", (char*) &u + PTR_TO_SIZE(userdata));
}
static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) { static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata; Context *c = userdata;
const char *name; const char *name;
@ -627,13 +618,27 @@ static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *
static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) { static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Context *c = userdata; Context *c = userdata;
bool has_uuid = false;
int interactive, r; int interactive, r;
sd_id128_t uuid;
assert(m); assert(m);
assert(c); assert(c);
if (!c->has_uuid) r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID, "Failed to read product UUID from /sys/class/dmi/id/product_uuid"); if (r == -ENOENT)
r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &uuid);
if (r < 0)
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to read product UUID, ignoring: %m");
else if (sd_id128_is_null(uuid) || sd_id128_is_allf(uuid))
log_debug("DMI product UUID " SD_ID128_FORMAT_STR " is all 0x00 or all 0xFF, ignoring.", SD_ID128_FORMAT_VAL(uuid));
else
has_uuid = true;
if (!has_uuid)
return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID,
"Failed to read product UUID from firmware.");
r = sd_bus_message_read(m, "b", &interactive); r = sd_bus_message_read(m, "b", &interactive);
if (r < 0) if (r < 0)
@ -657,7 +662,7 @@ static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_err
if (r < 0) if (r < 0)
return r; return r;
r = sd_bus_message_append_array(reply, 'y', &c->uuid, sizeof(c->uuid)); r = sd_bus_message_append_array(reply, 'y', &uuid, sizeof(uuid));
if (r < 0) if (r < 0)
return r; return r;
@ -673,9 +678,9 @@ static const sd_bus_vtable hostname_vtable[] = {
SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Deployment", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Deployment", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Location", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Location", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field, offsetof(struct utsname, sysname), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field, offsetof(struct utsname, release), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KernelVersion", "s", property_get_uname_field, offsetof(struct utsname, version), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HomeURL", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("HomeURL", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST),
@ -780,7 +785,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
} }
static int run(int argc, char *argv[]) { static int run(int argc, char *argv[]) {
_cleanup_(context_clear) Context context = {}; _cleanup_(context_destroy) Context context = {};
_cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r; int r;

View File

@ -410,5 +410,5 @@ int open_journal_for_upload(Uploader *u,
cursor); cursor);
} }
return process_journal_input(u, 1 + !!after_cursor); return process_journal_input(u, !!after_cursor);
} }

View File

@ -253,7 +253,8 @@ static int dhcp6_client_set_duid_internal(
r = dhcp_validate_duid_len(duid_type, duid_len, false); r = dhcp_validate_duid_len(duid_type, duid_len, false);
if (r < 0) if (r < 0)
return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m"); return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m");
log_dhcp6_client(client, "Setting DUID of type %u with unexpected content", duid_type);
log_dhcp6_client(client, "Using DUID of type %u of incorrect length, proceeding.", duid_type);
} }
client->duid.type = htobe16(duid_type); client->duid.type = htobe16(duid_type);

View File

@ -99,6 +99,7 @@ static int acquire_user_record(
_cleanup_(user_record_unrefp) UserRecord *ur = NULL; _cleanup_(user_record_unrefp) UserRecord *ur = NULL;
const char *username = NULL, *json = NULL; const char *username = NULL, *json = NULL;
_cleanup_free_ char *field = NULL;
int r; int r;
assert(handle); assert(handle);
@ -114,39 +115,18 @@ static int acquire_user_record(
return PAM_SERVICE_ERR; return PAM_SERVICE_ERR;
} }
/* If pam_systemd_homed (or some other module) already acqired the user record we can reuse it /* If pam_systemd_homed (or some other module) already acquired the user record we can reuse it
* here. */ * here. */
r = pam_get_data(handle, "systemd-user-record", (const void**) &json); field = strjoin("systemd-user-record-", username);
if (r != PAM_SUCCESS || !json) { if (!field)
_cleanup_free_ char *formatted = NULL; return pam_log_oom(handle);
r = pam_get_data(handle, field, (const void**) &json);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) { if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r)); pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r));
return r; return r;
} }
if (r == PAM_SUCCESS && json) {
/* Request the record ourselves */
r = userdb_by_name(username, 0, &ur);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to get user record: %s", strerror_safe(r));
return PAM_USER_UNKNOWN;
}
r = json_variant_format(ur->json, 0, &formatted);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to format user JSON: %s", strerror_safe(r));
return PAM_SERVICE_ERR;
}
/* And cache it for everyone else */
r = pam_set_data(handle, "systemd-user-record", formatted, pam_cleanup_free);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data: %s", pam_strerror(handle, r));
return r;
}
TAKE_PTR(formatted);
} else {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL; _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
/* Parse cached record */ /* Parse cached record */
@ -171,6 +151,31 @@ static int acquire_user_record(
pam_syslog(handle, LOG_ERR, "Acquired user record does not match user name."); pam_syslog(handle, LOG_ERR, "Acquired user record does not match user name.");
return PAM_SERVICE_ERR; return PAM_SERVICE_ERR;
} }
} else {
_cleanup_free_ char *formatted = NULL;
/* Request the record ourselves */
r = userdb_by_name(username, 0, &ur);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to get user record: %s", strerror_safe(r));
return PAM_USER_UNKNOWN;
}
r = json_variant_format(ur->json, 0, &formatted);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to format user JSON: %s", strerror_safe(r));
return PAM_SERVICE_ERR;
}
/* And cache it for everyone else */
r = pam_set_data(handle, field, formatted, pam_cleanup_free);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s': %s",
field, pam_strerror(handle, r));
return r;
}
TAKE_PTR(formatted);
} }
if (!uid_is_valid(ur->uid)) { if (!uid_is_valid(ur->uid)) {

View File

@ -4,25 +4,11 @@
#include "conf-parser.h" #include "conf-parser.h"
#include "ipvlan.h" #include "ipvlan.h"
#include "ipvlan-util.h"
#include "networkd-link.h" #include "networkd-link.h"
#include "string-table.h" #include "string-util.h"
static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = {
[NETDEV_IPVLAN_MODE_L2] = "L2",
[NETDEV_IPVLAN_MODE_L3] = "L3",
[NETDEV_IPVLAN_MODE_L3S] = "L3S",
};
DEFINE_STRING_TABLE_LOOKUP(ipvlan_mode, IPVlanMode);
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_mode, ipvlan_mode, IPVlanMode, "Failed to parse ipvlan mode"); DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_mode, ipvlan_mode, IPVlanMode, "Failed to parse ipvlan mode");
static const char* const ipvlan_flags_table[_NETDEV_IPVLAN_FLAGS_MAX] = {
[NETDEV_IPVLAN_FLAGS_BRIGDE] = "bridge",
[NETDEV_IPVLAN_FLAGS_PRIVATE] = "private",
[NETDEV_IPVLAN_FLAGS_VEPA] = "vepa",
};
DEFINE_STRING_TABLE_LOOKUP(ipvlan_flags, IPVlanFlags);
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_flags, ipvlan_flags, IPVlanFlags, "Failed to parse ipvlan flags"); DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_flags, ipvlan_flags, IPVlanFlags, "Failed to parse ipvlan flags");
static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) { static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {

View File

@ -4,24 +4,9 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <linux/if_link.h> #include <linux/if_link.h>
#include "ipvlan-util.h"
#include "netdev.h" #include "netdev.h"
typedef enum IPVlanMode {
NETDEV_IPVLAN_MODE_L2 = IPVLAN_MODE_L2,
NETDEV_IPVLAN_MODE_L3 = IPVLAN_MODE_L3,
NETDEV_IPVLAN_MODE_L3S = IPVLAN_MODE_L3S,
_NETDEV_IPVLAN_MODE_MAX,
_NETDEV_IPVLAN_MODE_INVALID = -1
} IPVlanMode;
typedef enum IPVlanFlags {
NETDEV_IPVLAN_FLAGS_BRIGDE,
NETDEV_IPVLAN_FLAGS_PRIVATE = IPVLAN_F_PRIVATE,
NETDEV_IPVLAN_FLAGS_VEPA = IPVLAN_F_VEPA,
_NETDEV_IPVLAN_FLAGS_MAX,
_NETDEV_IPVLAN_FLAGS_INVALID = -1
} IPVlanFlags;
typedef struct IPVlan { typedef struct IPVlan {
NetDev meta; NetDev meta;
@ -34,12 +19,6 @@ DEFINE_NETDEV_CAST(IPVTAP, IPVlan);
extern const NetDevVTable ipvlan_vtable; extern const NetDevVTable ipvlan_vtable;
extern const NetDevVTable ipvtap_vtable; extern const NetDevVTable ipvtap_vtable;
const char *ipvlan_mode_to_string(IPVlanMode d) _const_;
IPVlanMode ipvlan_mode_from_string(const char *d) _pure_;
const char *ipvlan_flags_to_string(IPVlanFlags d) _const_;
IPVlanFlags ipvlan_flags_from_string(const char *d) _pure_;
CONFIG_PARSER_PROTOTYPE(config_parse_ipvlan_mode); CONFIG_PARSER_PROTOTYPE(config_parse_ipvlan_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_ipvlan_flags); CONFIG_PARSER_PROTOTYPE(config_parse_ipvlan_flags);

View File

@ -33,6 +33,7 @@
#include "geneve-util.h" #include "geneve-util.h"
#include "glob-util.h" #include "glob-util.h"
#include "hwdb-util.h" #include "hwdb-util.h"
#include "ipvlan-util.h"
#include "local-addresses.h" #include "local-addresses.h"
#include "locale-util.h" #include "locale-util.h"
#include "logs-show.h" #include "logs-show.h"
@ -192,6 +193,10 @@ typedef struct LinkInfo {
/* macvlan and macvtap info */ /* macvlan and macvtap info */
uint32_t macvlan_mode; uint32_t macvlan_mode;
/* ipvlan info */
uint16_t ipvlan_mode;
uint16_t ipvlan_flags;
/* ethtool info */ /* ethtool info */
int autonegotiation; int autonegotiation;
uint64_t speed; uint64_t speed;
@ -335,6 +340,10 @@ static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
(void) sd_netlink_message_read_in6_addr(m, IFLA_VTI_REMOTE, &info->remote.in6); (void) sd_netlink_message_read_in6_addr(m, IFLA_VTI_REMOTE, &info->remote.in6);
} else if (STR_IN_SET(received_kind, "macvlan", "macvtap")) } else if (STR_IN_SET(received_kind, "macvlan", "macvtap"))
(void) sd_netlink_message_read_u32(m, IFLA_MACVLAN_MODE, &info->macvlan_mode); (void) sd_netlink_message_read_u32(m, IFLA_MACVLAN_MODE, &info->macvlan_mode);
else if (streq(received_kind, "ipvlan")) {
(void) sd_netlink_message_read_u16(m, IFLA_IPVLAN_MODE, &info->ipvlan_mode);
(void) sd_netlink_message_read_u16(m, IFLA_IPVLAN_FLAGS, &info->ipvlan_flags);
}
strncpy(info->netdev_kind, received_kind, IFNAMSIZ); strncpy(info->netdev_kind, received_kind, IFNAMSIZ);
@ -1798,6 +1807,28 @@ static int link_status_one(
TABLE_STRING, macvlan_mode_to_string(info->macvlan_mode)); TABLE_STRING, macvlan_mode_to_string(info->macvlan_mode));
if (r < 0) if (r < 0)
return table_log_add_error(r); return table_log_add_error(r);
} else if (streq_ptr(info->netdev_kind, "ipvlan")) {
_cleanup_free_ char *p = NULL, *s = NULL;
if (info->ipvlan_flags & IPVLAN_F_PRIVATE)
p = strdup("private");
else if (info->ipvlan_flags & IPVLAN_F_VEPA)
p = strdup("vepa");
else
p = strdup("bridge");
if (!p)
log_oom();
s = strjoin(ipvlan_mode_to_string(info->ipvlan_mode), " (", p, ")");
if (!s)
return log_oom();
r = table_add_many(table,
TABLE_EMPTY,
TABLE_STRING, "Mode:",
TABLE_STRING, s);
if (r < 0)
return table_log_add_error(r);
} }
if (info->has_wlan_link_info) { if (info->has_wlan_link_info) {

View File

@ -546,30 +546,47 @@ static int condition_test_capability(Condition *c, char **env) {
} }
static int condition_test_needs_update(Condition *c, char **env) { static int condition_test_needs_update(Condition *c, char **env) {
const char *p;
struct stat usr, other; struct stat usr, other;
const char *p;
bool b;
int r;
assert(c); assert(c);
assert(c->parameter); assert(c->parameter);
assert(c->type == CONDITION_NEEDS_UPDATE); assert(c->type == CONDITION_NEEDS_UPDATE);
r = proc_cmdline_get_bool("systemd.condition-needs-update", &b);
if (r < 0)
log_debug_errno(r, "Failed to parse systemd.condition-needs-update= kernel command line argument, ignoring: %m");
if (r > 0)
return b;
if (!path_is_absolute(c->parameter)) {
log_debug("Specified condition parameter '%s' is not absolute, assuming an update is needed.", c->parameter);
return true;
}
/* If the file system is read-only we shouldn't suggest an update */ /* If the file system is read-only we shouldn't suggest an update */
if (path_is_read_only_fs(c->parameter) > 0) r = path_is_read_only_fs(c->parameter);
if (r < 0)
log_debug_errno(r, "Failed to determine if '%s' is read-only, ignoring: %m", c->parameter);
if (r > 0)
return false; return false;
/* Any other failure means we should allow the condition to be true, /* Any other failure means we should allow the condition to be true, so that we rather invoke too
* so that we rather invoke too many update tools than too * many update tools than too few. */
* few. */
if (!path_is_absolute(c->parameter))
return true;
p = strjoina(c->parameter, "/.updated"); p = strjoina(c->parameter, "/.updated");
if (lstat(p, &other) < 0) if (lstat(p, &other) < 0) {
if (errno != ENOENT)
log_debug_errno(errno, "Failed to stat() '%s', assuming an update is needed: %m", p);
return true; return true;
}
if (lstat("/usr/", &usr) < 0) if (lstat("/usr/", &usr) < 0) {
log_debug_errno(errno, "Failed to stat() /usr/, assuming an update is needed: %m");
return true; return true;
}
/* /*
* First, compare seconds as they are always accurate... * First, compare seconds as they are always accurate...
@ -585,44 +602,52 @@ static int condition_test_needs_update(Condition *c, char **env) {
* AND the target file's nanoseconds == 0 * AND the target file's nanoseconds == 0
* (otherwise the filesystem supports nsec timestamps, see stat(2)). * (otherwise the filesystem supports nsec timestamps, see stat(2)).
*/ */
if (usr.st_mtim.tv_nsec > 0 && other.st_mtim.tv_nsec == 0) { if (usr.st_mtim.tv_nsec == 0 || other.st_mtim.tv_nsec > 0)
_cleanup_free_ char *timestamp_str = NULL; return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
uint64_t timestamp;
int r;
_cleanup_free_ char *timestamp_str = NULL;
r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", &timestamp_str); r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", &timestamp_str);
if (r < 0) { if (r < 0) {
log_error_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p); log_debug_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
return true; return true;
} else if (r == 0) { } else if (r == 0) {
log_debug("No data in timestamp file '%s', using mtime", p); log_debug("No data in timestamp file '%s', using mtime.", p);
return true; return true;
} }
uint64_t timestamp;
r = safe_atou64(timestamp_str, &timestamp); r = safe_atou64(timestamp_str, &timestamp);
if (r < 0) { if (r < 0) {
log_error_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p); log_debug_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
return true; return true;
} }
timespec_store(&other.st_mtim, timestamp); return timespec_load_nsec(&usr.st_mtim) > timestamp;
}
return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
} }
static int condition_test_first_boot(Condition *c, char **env) { static int condition_test_first_boot(Condition *c, char **env) {
int r; int r, q;
bool b;
assert(c); assert(c);
assert(c->parameter); assert(c->parameter);
assert(c->type == CONDITION_FIRST_BOOT); assert(c->type == CONDITION_FIRST_BOOT);
r = proc_cmdline_get_bool("systemd.condition-first-boot", &b);
if (r < 0)
log_debug_errno(r, "Failed to parse systemd.condition-first-boot= kernel command line argument, ignoring: %m");
if (r > 0)
return b == !!r;
r = parse_boolean(c->parameter); r = parse_boolean(c->parameter);
if (r < 0) if (r < 0)
return r; return r;
return (access("/run/systemd/first-boot", F_OK) >= 0) == !!r; q = access("/run/systemd/first-boot", F_OK);
if (q < 0 && errno != ENOENT)
log_debug_errno(errno, "Failed to check if /run/systemd/first-boot exists, ignoring: %m");
return (q >= 0) == !!r;
} }
static int condition_test_environment(Condition *c, char **env) { static int condition_test_environment(Condition *c, char **env) {

22
src/shared/ipvlan-util.c Normal file
View File

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <net/if.h>
#include "ipvlan-util.h"
#include "string-table.h"
static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = {
[NETDEV_IPVLAN_MODE_L2] = "L2",
[NETDEV_IPVLAN_MODE_L3] = "L3",
[NETDEV_IPVLAN_MODE_L3S] = "L3S",
};
DEFINE_STRING_TABLE_LOOKUP(ipvlan_mode, IPVlanMode);
static const char* const ipvlan_flags_table[_NETDEV_IPVLAN_FLAGS_MAX] = {
[NETDEV_IPVLAN_FLAGS_BRIGDE] = "bridge",
[NETDEV_IPVLAN_FLAGS_PRIVATE] = "private",
[NETDEV_IPVLAN_FLAGS_VEPA] = "vepa",
};
DEFINE_STRING_TABLE_LOOKUP(ipvlan_flags, IPVlanFlags);

29
src/shared/ipvlan-util.h Normal file
View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <netinet/in.h>
#include <linux/if_link.h>
#include "macro.h"
typedef enum IPVlanMode {
NETDEV_IPVLAN_MODE_L2 = IPVLAN_MODE_L2,
NETDEV_IPVLAN_MODE_L3 = IPVLAN_MODE_L3,
NETDEV_IPVLAN_MODE_L3S = IPVLAN_MODE_L3S,
_NETDEV_IPVLAN_MODE_MAX,
_NETDEV_IPVLAN_MODE_INVALID = -1
} IPVlanMode;
typedef enum IPVlanFlags {
NETDEV_IPVLAN_FLAGS_BRIGDE,
NETDEV_IPVLAN_FLAGS_PRIVATE = IPVLAN_F_PRIVATE,
NETDEV_IPVLAN_FLAGS_VEPA = IPVLAN_F_VEPA,
_NETDEV_IPVLAN_FLAGS_MAX,
_NETDEV_IPVLAN_FLAGS_INVALID = -1
} IPVlanFlags;
const char *ipvlan_mode_to_string(IPVlanMode d) _const_;
IPVlanMode ipvlan_mode_from_string(const char *d) _pure_;
const char *ipvlan_flags_to_string(IPVlanFlags d) _const_;
IPVlanFlags ipvlan_flags_from_string(const char *d) _pure_;

View File

@ -120,6 +120,8 @@ shared_sources = files('''
install-printf.h install-printf.h
install.c install.c
install.h install.h
ipvlan-util.c
ipvlan-util.h
ip-protocol-list.c ip-protocol-list.c
ip-protocol-list.h ip-protocol-list.h
journal-importer.c journal-importer.c

View File

@ -24,15 +24,15 @@ units = [
['hibernate.target', 'ENABLE_HIBERNATE'], ['hibernate.target', 'ENABLE_HIBERNATE'],
['hybrid-sleep.target', 'ENABLE_HIBERNATE'], ['hybrid-sleep.target', 'ENABLE_HIBERNATE'],
['suspend-then-hibernate.target', 'ENABLE_HIBERNATE'], ['suspend-then-hibernate.target', 'ENABLE_HIBERNATE'],
['initrd-cleanup.service', ''], ['initrd-cleanup.service', 'ENABLE_INITRD'],
['initrd-fs.target', ''], ['initrd-fs.target', 'ENABLE_INITRD'],
['initrd-parse-etc.service', ''], ['initrd-parse-etc.service', 'ENABLE_INITRD'],
['initrd-root-device.target', ''], ['initrd-root-device.target', 'ENABLE_INITRD'],
['initrd-root-fs.target', ''], ['initrd-root-fs.target', 'ENABLE_INITRD'],
['initrd-switch-root.service', ''], ['initrd-switch-root.service', 'ENABLE_INITRD'],
['initrd-switch-root.target', ''], ['initrd-switch-root.target', 'ENABLE_INITRD'],
['initrd-udevadm-cleanup-db.service', ''], ['initrd-udevadm-cleanup-db.service', 'ENABLE_INITRD'],
['initrd.target', ''], ['initrd.target', 'ENABLE_INITRD'],
['kexec.target', ''], ['kexec.target', ''],
['ldconfig.service', 'ENABLE_LDCONFIG', ['ldconfig.service', 'ENABLE_LDCONFIG',
'sysinit.target.wants/'], 'sysinit.target.wants/'],
@ -225,7 +225,7 @@ in_units = [
['systemd-user-sessions.service', 'HAVE_PAM', ['systemd-user-sessions.service', 'HAVE_PAM',
'multi-user.target.wants/'], 'multi-user.target.wants/'],
['systemd-vconsole-setup.service', 'ENABLE_VCONSOLE'], ['systemd-vconsole-setup.service', 'ENABLE_VCONSOLE'],
['systemd-volatile-root.service', ''], ['systemd-volatile-root.service', 'ENABLE_INITRD'],
['systemd-repart.service', 'ENABLE_REPART', ['systemd-repart.service', 'ENABLE_REPART',
'sysinit.target.wants/ initrd-root-fs.target.wants/'], 'sysinit.target.wants/ initrd-root-fs.target.wants/'],
['user-runtime-dir@.service', ''], ['user-runtime-dir@.service', ''],