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

Compare commits

..

No commits in common. "44dcb318cc44c0830ec9ebfbf35eca2b3f67f9fd" and "34d16bad2d07444dcdae380480f5cc8c5eea8eaa" have entirely different histories.

26 changed files with 240 additions and 498 deletions

View File

@ -18,7 +18,6 @@ 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,7 +8,6 @@ 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,7 +252,8 @@ 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: to force random seed crediting * maybe add kernel cmdline params: 1) to force first-boot mode + 2) to force
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,47 +433,8 @@
<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 will not query the user for basic system settings, even if the system boots up for the first time and the
the relevant settings are not initialized yet. Not to be confused with relevant settings are not initialized yet.</para></listitem>
<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,10 +58,6 @@
<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,13 +1294,6 @@
<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>
@ -1312,10 +1305,6 @@
(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,10 +90,6 @@ 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)
@ -1423,7 +1419,6 @@ 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)
@ -2771,7 +2766,7 @@ executable(
include_directories : includes, include_directories : includes,
link_with : [libshared], link_with : [libshared],
install_rpath : rootlibexecdir, install_rpath : rootlibexecdir,
install : conf.get('ENABLE_INITRD') == 1, install : true,
install_dir : rootlibexecdir) install_dir : rootlibexecdir)
executable( executable(
@ -3544,7 +3539,6 @@ foreach tuple : [
['openssl'], ['openssl'],
['libcurl'], ['libcurl'],
['idn'], ['idn'],
['initrd'],
['libidn2'], ['libidn2'],
['libidn'], ['libidn'],
['libiptc'], ['libiptc'],

View File

@ -35,8 +35,6 @@ 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) { /* key not specified at all */ if (r == 0) {
*ret = false; *ret = false;
return 0; return 0;
} }
if (v) { /* key with parameter passed */ if (v) { /* 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 /* key without parameter passed */ } else /* no 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, /* automatically strip "rd." prefix if it is set (and we are in the initrd, since otherwise we'd not consider it anyway) */ PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0,
PROC_CMDLINE_VALUE_OPTIONAL = 1 << 1, /* the value is optional (for boolean switches that can omit the value) */ PROC_CMDLINE_VALUE_OPTIONAL = 1 << 1,
PROC_CMDLINE_RD_STRICT = 1 << 2, /* ignore this in the initrd */ PROC_CMDLINE_RD_STRICT = 1 << 2,
} 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,41 +10,29 @@
#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); r = read_etc_hostname(NULL, &b);
if (r < 0) if (r < 0) {
log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m"); if (r == -ENOENT)
else if (r > 0) { enoent = true;
if (hostname_is_valid(b, true)) else
hn = b; log_warning_errno(r, "Failed to read configured hostname: %m");
else {
log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b);
b = mfree(b);
}
}
if (!hn) { hn = NULL;
r = read_etc_hostname(NULL, &b); } else
if (r < 0) { hn = b;
if (r == -ENOENT)
enoent = true;
else
log_warning_errno(r, "Failed to read configured hostname: %m");
} else
hn = b;
}
if (isempty(hn)) { if (isempty(hn)) {
/* Don't override the hostname if it is already set and not explicitly configured */ /* Don't override the hostname if it is already set
* and not explicitly configured */
if (hostname_is_set()) if (hostname_is_set())
return 0; return 0;

View File

@ -146,7 +146,6 @@ 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;
@ -492,15 +491,6 @@ 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)
@ -1514,9 +1504,6 @@ 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;
@ -1555,25 +1542,6 @@ 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)
@ -2690,8 +2658,6 @@ 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
[Home] [Resolve]
#DefaultStorage= #DefaultStorage=
#DefaultFileSystemType=ext4 #DefaultFileSystemType=ext4

View File

@ -18,6 +18,11 @@
#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,
@ -62,30 +67,27 @@ 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;
_cleanup_free_ char *homed_field = NULL; const char *username = NULL, *json = NULL;
const char *json = NULL; const void *b = 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)); return r;
return r; }
}
if (isempty(username)) { if (isempty(username)) {
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
@ -93,30 +95,31 @@ static int acquire_user_record(
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;
/* We cache the user record in the PAM context. We use a field name that includes the username, since /* Let's check if a previous run determined that this user is not managed by homed. If so, let's exit early */
* clients might change the user name associated with a PAM context underneath us. Notably, 'sudo' r = pam_get_data(handle, "systemd-user-record-is-homed", &b);
* creates a single PAM context and first authenticates it with the user set to the originating user,
* then updates the user for the destination user and issues the session stack with the same PAM
* context. We thus must be prepared that the user record changes between calls and we keep any
* caching separate. */
homed_field = strjoin("systemd-home-user-record-", username);
if (!homed_field)
return pam_log_oom(handle);
/* Let's use the cache, so that we can share it between the session and the authentication hooks */
r = pam_get_data(handle, homed_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)); /* Failure */
pam_syslog(handle, LOG_ERR, "Failed to get PAM user-record-is-homed flag: %s", pam_strerror(handle, r));
return r; return r;
} else if (b == NULL)
/* Nothing cached yet, need to acquire fresh */
json = NULL;
else if (b != USER_RECORD_IS_HOMED)
/* Definitely not a homed record */
return PAM_USER_UNKNOWN;
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)) {
pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, 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 *generic_field = NULL, *json_copy = NULL; _cleanup_free_ char *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)
@ -143,38 +146,23 @@ 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, homed_field, json_copy, pam_cleanup_free); r = pam_set_data(handle, "systemd-user-record", 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': %s", pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data: %s", pam_strerror(handle, r));
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);
@ -193,7 +181,6 @@ 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;
@ -206,36 +193,23 @@ 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, homed_field, (void*) -1, NULL); r = pam_set_data(handle, "systemd-user-record-is-homed", USER_RECORD_IS_OTHER, NULL);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s' to invalid, ignoring: %s", pam_syslog(handle, LOG_ERR, "Failed to set PAM user-record-is-homed flag, ignoring: %s", pam_strerror(handle, r));
homed_field, pam_strerror(handle, r));
return PAM_USER_UNKNOWN; return PAM_USER_UNKNOWN;
} }
static int release_user_record(pam_handle_t *handle, const char *username) { static int release_user_record(pam_handle_t *handle) {
_cleanup_free_ char *homed_field = NULL, *generic_field = NULL;
int r, k; int r, k;
assert(handle); r = pam_set_data(handle, "systemd-user-record", NULL, NULL);
assert(username);
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) if (r != PAM_SUCCESS)
pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data '%s': %s", homed_field, pam_strerror(handle, r)); pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data: %s", pam_strerror(handle, r));
generic_field = strjoin("systemd-user-record-", username); k = pam_set_data(handle, "systemd-user-record-is-homed", NULL, NULL);
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 data '%s': %s", generic_field, pam_strerror(handle, k)); pam_syslog(handle, LOG_ERR, "Failed to release PAM user-record-is-homed flag: %s", 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;
} }
@ -421,9 +395,7 @@ 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;
@ -437,27 +409,8 @@ 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 */
fd_field = strjoin("systemd-home-fd-", username); r = pam_get_data(handle, "systemd-home-fd", &home_fd_ptr);
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;
@ -465,7 +418,7 @@ static int acquire_home(
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
r = acquire_user_record(handle, username, &ur); r = acquire_user_record(handle, &ur);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
@ -581,7 +534,7 @@ static int acquire_home(
do_auth = true; do_auth = true;
} }
r = pam_set_data(handle, fd_field, FD_TO_PTR(acquired_fd), cleanup_home_fd); r = pam_set_data(handle, "systemd-home-fd", 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;
@ -592,7 +545,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, ur->user_name); r = release_user_record(handle);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return r; return r;
} }
@ -602,27 +555,15 @@ static int acquire_home(
return PAM_SUCCESS; return PAM_SUCCESS;
} }
static int release_home_fd(pam_handle_t *handle, const char *username) { static int release_home_fd(pam_handle_t *handle) {
_cleanup_free_ char *fd_field = NULL;
const void *home_fd_ptr = NULL; const void *home_fd_ptr = NULL;
int r; int r;
assert(handle); r = pam_get_data(handle, "systemd-home-fd", &home_fd_ptr);
assert(username); if (r == PAM_NO_MODULE_DATA || PTR_TO_FD(home_fd_ptr) < 0)
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; 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); r = pam_set_data(handle, "systemd-home-fd", 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));
@ -709,25 +650,20 @@ _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;
@ -779,7 +715,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, NULL, &ur); r = acquire_user_record(handle, &ur);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
@ -887,7 +823,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, NULL, &ur); r = acquire_user_record(handle, &ur);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;

View File

@ -43,6 +43,9 @@ 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,
@ -52,6 +55,8 @@ 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) {
@ -63,7 +68,7 @@ static void context_reset(Context *c) {
c->data[p] = mfree(c->data[p]); c->data[p] = mfree(c->data[p]);
} }
static void context_destroy(Context *c) { static void context_clear(Context *c) {
assert(c); assert(c);
context_reset(c); context_reset(c);
@ -72,11 +77,20 @@ static void context_destroy(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;
@ -102,6 +116,17 @@ 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;
} }
@ -386,22 +411,6 @@ 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;
@ -618,27 +627,13 @@ 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);
r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid); if (!c->has_uuid)
if (r == -ENOENT) return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID, "Failed to read product UUID from /sys/class/dmi/id/product_uuid");
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)
@ -662,7 +657,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', &uuid, sizeof(uuid)); r = sd_bus_message_append_array(reply, 'y', &c->uuid, sizeof(c->uuid));
if (r < 0) if (r < 0)
return r; return r;
@ -678,9 +673,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", property_get_uname_field, offsetof(struct utsname, sysname), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, 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("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, 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("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, 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),
@ -785,7 +780,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_destroy) Context context = {}; _cleanup_(context_clear) 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, !!after_cursor); return process_journal_input(u, 1 + !!after_cursor);
} }

View File

@ -253,8 +253,7 @@ 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,7 +99,6 @@ 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);
@ -115,18 +114,39 @@ static int acquire_user_record(
return PAM_SERVICE_ERR; return PAM_SERVICE_ERR;
} }
/* If pam_systemd_homed (or some other module) already acquired the user record we can reuse it /* If pam_systemd_homed (or some other module) already acqired the user record we can reuse it
* here. */ * here. */
field = strjoin("systemd-user-record-", username); r = pam_get_data(handle, "systemd-user-record", (const void**) &json);
if (!field) if (r != PAM_SUCCESS || !json) {
return pam_log_oom(handle); _cleanup_free_ char *formatted = NULL;
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 */
@ -151,31 +171,6 @@ 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,11 +4,25 @@
#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-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);
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,9 +4,24 @@
#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;
@ -19,6 +34,12 @@ 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,7 +33,6 @@
#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"
@ -193,10 +192,6 @@ 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;
@ -340,10 +335,6 @@ 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);
@ -1807,28 +1798,6 @@ 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,47 +546,30 @@ 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) {
struct stat usr, other;
const char *p; const char *p;
bool b; struct stat usr, other;
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 */
r = path_is_read_only_fs(c->parameter); if (path_is_read_only_fs(c->parameter) > 0)
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, so that we rather invoke too /* Any other failure means we should allow the condition to be true,
* many update tools than too few. */ * so that we rather invoke too many update tools than too
* 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...
@ -602,52 +585,44 @@ 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) {
return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec; _cleanup_free_ char *timestamp_str = NULL;
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; }
r = safe_atou64(timestamp_str, &timestamp);
if (r < 0) {
log_error_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
return true;
}
timespec_store(&other.st_mtim, timestamp);
} }
uint64_t timestamp; return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
r = safe_atou64(timestamp_str, &timestamp);
if (r < 0) {
log_debug_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
return true;
}
return timespec_load_nsec(&usr.st_mtim) > timestamp;
} }
static int condition_test_first_boot(Condition *c, char **env) { static int condition_test_first_boot(Condition *c, char **env) {
int r, q; int r;
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;
q = access("/run/systemd/first-boot", F_OK); return (access("/run/systemd/first-boot", F_OK) >= 0) == !!r;
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) {

View File

@ -1,22 +0,0 @@
/* 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);

View File

@ -1,29 +0,0 @@
/* 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,8 +120,6 @@ 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', 'ENABLE_INITRD'], ['initrd-cleanup.service', ''],
['initrd-fs.target', 'ENABLE_INITRD'], ['initrd-fs.target', ''],
['initrd-parse-etc.service', 'ENABLE_INITRD'], ['initrd-parse-etc.service', ''],
['initrd-root-device.target', 'ENABLE_INITRD'], ['initrd-root-device.target', ''],
['initrd-root-fs.target', 'ENABLE_INITRD'], ['initrd-root-fs.target', ''],
['initrd-switch-root.service', 'ENABLE_INITRD'], ['initrd-switch-root.service', ''],
['initrd-switch-root.target', 'ENABLE_INITRD'], ['initrd-switch-root.target', ''],
['initrd-udevadm-cleanup-db.service', 'ENABLE_INITRD'], ['initrd-udevadm-cleanup-db.service', ''],
['initrd.target', 'ENABLE_INITRD'], ['initrd.target', ''],
['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', 'ENABLE_INITRD'], ['systemd-volatile-root.service', ''],
['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', ''],