mirror of
https://github.com/systemd/systemd
synced 2025-12-24 01:44:46 +01:00
Compare commits
30 Commits
34d16bad2d
...
44dcb318cc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44dcb318cc | ||
|
|
cdf7ad38b6 | ||
|
|
5e375a1ef2 | ||
|
|
201fa8f256 | ||
|
|
c5dc0a298e | ||
|
|
619720ba0a | ||
|
|
01bcea4999 | ||
|
|
e2cf880e68 | ||
|
|
82d7a25ee6 | ||
|
|
bc48b25afd | ||
|
|
abc72137d1 | ||
|
|
cfb9433de4 | ||
|
|
5704cd733c | ||
|
|
72f48cd3e3 | ||
|
|
c6526b8d66 | ||
|
|
34293dfafd | ||
|
|
3753325bef | ||
|
|
814872e925 | ||
|
|
5439d8212c | ||
|
|
ce0f7f5546 | ||
|
|
f8b4ae29c7 | ||
|
|
3931056767 | ||
|
|
b2d1ad757c | ||
|
|
f33cd69b5c | ||
|
|
df1f5dc1d9 | ||
|
|
841c0987f7 | ||
|
|
851ef1ed56 | ||
|
|
35072050e6 | ||
|
|
6c8428bb8b | ||
|
|
dbe7fff476 |
1
.github/workflows/main.yml
vendored
1
.github/workflows/main.yml
vendored
@ -18,6 +18,7 @@ on:
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'systemd/systemd'
|
||||
steps:
|
||||
- name: Build Fuzzers
|
||||
id: build
|
||||
|
||||
@ -8,6 +8,7 @@ System and Service Manager
|
||||
[](https://scan.coverity.com/projects/350)<br/>
|
||||
[](https://app.fuzzit.dev/orgs/systemd/dashboard)<br/>
|
||||
[](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#systemd)<br/>
|
||||
[](https://github.com/systemd/systemd/actions)<br/>
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/1369)<br/>
|
||||
[](https://travis-ci.org/systemd/systemd)<br/>
|
||||
[](https://lgtm.com/projects/g/systemd/systemd/context:cpp)<br/>
|
||||
|
||||
3
TODO
3
TODO
@ -252,8 +252,7 @@ Features:
|
||||
that are linked to these places instead of copied. After all they are
|
||||
constant vendor data.
|
||||
|
||||
* maybe add kernel cmdline params: 1) to force first-boot mode + 2) to force
|
||||
random seed crediting
|
||||
* maybe add kernel cmdline params: to force random seed crediting
|
||||
|
||||
* nspawn: on cgroupsv1 issue cgroup empty handler process based on host events,
|
||||
so that we make cgroup agent logic safe
|
||||
|
||||
@ -433,8 +433,47 @@
|
||||
|
||||
<listitem><para>Takes a boolean argument, defaults to on. If off,
|
||||
<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
|
||||
relevant settings are not initialized yet.</para></listitem>
|
||||
will not query the user for basic system settings, even if the system boots up for the first time and
|
||||
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>
|
||||
</variablelist>
|
||||
|
||||
|
||||
@ -58,6 +58,10 @@
|
||||
<citerefentry project='man-pages'><refentrytitle>touch</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
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>
|
||||
|
||||
@ -1294,6 +1294,13 @@
|
||||
<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
|
||||
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>
|
||||
</varlistentry>
|
||||
|
||||
@ -1305,6 +1312,10 @@
|
||||
(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
|
||||
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>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
@ -90,6 +90,10 @@ sysvrcnd_path = get_option('sysvrcnd-path')
|
||||
conf.set10('HAVE_SYSV_COMPAT', sysvinit_path != '' and sysvrcnd_path != '',
|
||||
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_NR_OPEN', get_option('bump-proc-sys-fs-nr-open'))
|
||||
conf.set('HIGH_RLIMIT_NOFILE', 512*1024)
|
||||
@ -1419,6 +1423,7 @@ foreach term : ['utmp',
|
||||
'smack',
|
||||
'gshadow',
|
||||
'idn',
|
||||
'initrd',
|
||||
'nss-myhostname',
|
||||
'nss-systemd']
|
||||
have = get_option(term)
|
||||
@ -2766,7 +2771,7 @@ executable(
|
||||
include_directories : includes,
|
||||
link_with : [libshared],
|
||||
install_rpath : rootlibexecdir,
|
||||
install : true,
|
||||
install : conf.get('ENABLE_INITRD') == 1,
|
||||
install_dir : rootlibexecdir)
|
||||
|
||||
executable(
|
||||
@ -3539,6 +3544,7 @@ foreach tuple : [
|
||||
['openssl'],
|
||||
['libcurl'],
|
||||
['idn'],
|
||||
['initrd'],
|
||||
['libidn2'],
|
||||
['libidn'],
|
||||
['libiptc'],
|
||||
|
||||
@ -35,6 +35,8 @@ option('telinit-path', type : 'string', value : '/lib/sysvinit/telinit',
|
||||
description : 'path to telinit')
|
||||
option('rc-local', type : 'string',
|
||||
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('quotacheck-path', type : 'string', description : 'path to quotacheck')
|
||||
|
||||
@ -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);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
if (r == 0) { /* key not specified at all */
|
||||
*ret = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (v) { /* parameter passed */
|
||||
if (v) { /* key with parameter passed */
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
*ret = r;
|
||||
} else /* no parameter passed */
|
||||
} else /* key without parameter passed */
|
||||
*ret = true;
|
||||
|
||||
return 1;
|
||||
|
||||
@ -6,9 +6,9 @@
|
||||
#include "log.h"
|
||||
|
||||
typedef enum ProcCmdlineFlags {
|
||||
PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0,
|
||||
PROC_CMDLINE_VALUE_OPTIONAL = 1 << 1,
|
||||
PROC_CMDLINE_RD_STRICT = 1 << 2,
|
||||
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, /* the value is optional (for boolean switches that can omit the value) */
|
||||
PROC_CMDLINE_RD_STRICT = 1 << 2, /* ignore this in the initrd */
|
||||
} ProcCmdlineFlags;
|
||||
|
||||
typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data);
|
||||
|
||||
@ -10,29 +10,41 @@
|
||||
#include "hostname-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
int hostname_setup(void) {
|
||||
_cleanup_free_ char *b = NULL;
|
||||
const char *hn = NULL;
|
||||
bool enoent = false;
|
||||
const char *hn;
|
||||
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);
|
||||
if (r < 0) {
|
||||
if (r == -ENOENT)
|
||||
enoent = true;
|
||||
else
|
||||
log_warning_errno(r, "Failed to read configured hostname: %m");
|
||||
|
||||
hn = NULL;
|
||||
} else
|
||||
hn = b;
|
||||
}
|
||||
|
||||
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())
|
||||
return 0;
|
||||
|
||||
|
||||
@ -146,6 +146,7 @@ static EmergencyAction arg_cad_burst_action;
|
||||
static OOMPolicy arg_default_oom_policy;
|
||||
static CPUSet arg_cpu_affinity;
|
||||
static NUMAPolicy arg_numa_policy;
|
||||
static usec_t arg_clock_usec;
|
||||
|
||||
/* A copy of the original environment block */
|
||||
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);
|
||||
|
||||
} 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) {
|
||||
|
||||
if (arg_show_status == _SHOW_STATUS_INVALID)
|
||||
@ -1504,6 +1514,9 @@ static int become_shutdown(
|
||||
static void initialize_clock(void) {
|
||||
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) {
|
||||
int min;
|
||||
|
||||
@ -1542,6 +1555,25 @@ static void initialize_clock(void) {
|
||||
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) {
|
||||
#if ENABLE_COREDUMP
|
||||
if (getpid_cached() != 1)
|
||||
@ -2658,6 +2690,8 @@ int main(int argc, char *argv[]) {
|
||||
assert_se(chdir("/") == 0);
|
||||
|
||||
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. */
|
||||
initialize_core_pattern(skip_setup);
|
||||
|
||||
@ -11,6 +11,6 @@
|
||||
#
|
||||
# See homed.conf(5) for details
|
||||
|
||||
[Resolve]
|
||||
[Home]
|
||||
#DefaultStorage=
|
||||
#DefaultFileSystemType=ext4
|
||||
|
||||
@ -18,11 +18,6 @@
|
||||
#include "user-record.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(
|
||||
pam_handle_t *handle,
|
||||
int argc, const char **argv,
|
||||
@ -67,18 +62,20 @@ static int parse_argv(
|
||||
|
||||
static int acquire_user_record(
|
||||
pam_handle_t *handle,
|
||||
const char *username,
|
||||
UserRecord **ret_record) {
|
||||
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
_cleanup_(user_record_unrefp) UserRecord *ur = NULL;
|
||||
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
|
||||
const char *username = NULL, *json = NULL;
|
||||
const void *b = NULL;
|
||||
_cleanup_free_ char *homed_field = NULL;
|
||||
const char *json = NULL;
|
||||
int r;
|
||||
|
||||
assert(handle);
|
||||
|
||||
if (!username) {
|
||||
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));
|
||||
@ -89,37 +86,37 @@ static int acquire_user_record(
|
||||
pam_syslog(handle, LOG_ERR, "User name not set.");
|
||||
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
|
||||
* user names we don't consider valid. */
|
||||
if (STR_IN_SET(username, "root", NOBODY_USER_NAME) || !valid_user_group_name(username, 0))
|
||||
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 */
|
||||
r = pam_get_data(handle, "systemd-user-record-is-homed", &b);
|
||||
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
|
||||
/* Failure */
|
||||
pam_syslog(handle, LOG_ERR, "Failed to get PAM user-record-is-homed flag: %s", pam_strerror(handle, 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);
|
||||
/* We cache the user record in the PAM context. We use a field name that includes the username, since
|
||||
* clients might change the user name associated with a PAM context underneath us. Notably, 'sudo'
|
||||
* 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)) {
|
||||
pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r));
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (!json) {
|
||||
if (r == PAM_SUCCESS && json) {
|
||||
/* We determined earlier that this is not a homed user? Then exit early. (We use -1 as
|
||||
* 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_free_ char *json_copy = NULL;
|
||||
_cleanup_free_ char *generic_field = NULL, *json_copy = NULL;
|
||||
|
||||
r = pam_acquire_bus_connection(handle, &bus);
|
||||
if (r != PAM_SUCCESS)
|
||||
@ -146,23 +143,38 @@ static int acquire_user_record(
|
||||
if (r < 0)
|
||||
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);
|
||||
if (!json_copy)
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
@ -181,6 +193,7 @@ static int acquire_user_record(
|
||||
return PAM_SERVICE_ERR;
|
||||
}
|
||||
|
||||
/* Safety check if cached record actually matches what we are looking for */
|
||||
if (!streq_ptr(username, ur->user_name)) {
|
||||
pam_syslog(handle, LOG_ERR, "Acquired user record does not match user name.");
|
||||
return PAM_SERVICE_ERR;
|
||||
@ -193,23 +206,36 @@ static int acquire_user_record(
|
||||
|
||||
user_unknown:
|
||||
/* 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)
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
r = pam_set_data(handle, "systemd-user-record", NULL, NULL);
|
||||
if (r != PAM_SUCCESS)
|
||||
pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data: %s", pam_strerror(handle, r));
|
||||
assert(handle);
|
||||
assert(username);
|
||||
|
||||
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)
|
||||
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;
|
||||
}
|
||||
@ -395,7 +421,9 @@ static int acquire_home(
|
||||
bool do_auth = please_authenticate, home_not_active = false, home_locked = false;
|
||||
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_close_ int acquired_fd = -1;
|
||||
_cleanup_free_ char *fd_field = NULL;
|
||||
const void *home_fd_ptr = NULL;
|
||||
const char *username = NULL;
|
||||
unsigned n_attempts = 0;
|
||||
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
|
||||
* 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 */
|
||||
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)
|
||||
return PAM_SUCCESS;
|
||||
|
||||
@ -418,7 +465,7 @@ static int acquire_home(
|
||||
if (r != PAM_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = acquire_user_record(handle, &ur);
|
||||
r = acquire_user_record(handle, username, &ur);
|
||||
if (r != PAM_SUCCESS)
|
||||
return r;
|
||||
|
||||
@ -534,7 +581,7 @@ static int acquire_home(
|
||||
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) {
|
||||
pam_syslog(handle, LOG_ERR, "Failed to set PAM bus data: %s", pam_strerror(handle, 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
|
||||
* 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))
|
||||
return r;
|
||||
}
|
||||
@ -555,15 +602,27 @@ static int acquire_home(
|
||||
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;
|
||||
int r;
|
||||
|
||||
r = pam_get_data(handle, "systemd-home-fd", &home_fd_ptr);
|
||||
if (r == PAM_NO_MODULE_DATA || PTR_TO_FD(home_fd_ptr) < 0)
|
||||
return PAM_NO_MODULE_DATA;
|
||||
assert(handle);
|
||||
assert(username);
|
||||
|
||||
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)
|
||||
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)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (r != PAM_SUCCESS)
|
||||
return r;
|
||||
@ -715,7 +779,7 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt(
|
||||
if (r != PAM_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = acquire_user_record(handle, &ur);
|
||||
r = acquire_user_record(handle, NULL, &ur);
|
||||
if (r != PAM_SUCCESS)
|
||||
return r;
|
||||
|
||||
@ -823,7 +887,7 @@ _public_ PAM_EXTERN int pam_sm_chauthtok(
|
||||
if (r != PAM_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = acquire_user_record(handle, &ur);
|
||||
r = acquire_user_record(handle, NULL, &ur);
|
||||
if (r != PAM_SUCCESS)
|
||||
return r;
|
||||
|
||||
|
||||
@ -43,9 +43,6 @@ enum {
|
||||
PROP_CHASSIS,
|
||||
PROP_DEPLOYMENT,
|
||||
PROP_LOCATION,
|
||||
PROP_KERNEL_NAME,
|
||||
PROP_KERNEL_RELEASE,
|
||||
PROP_KERNEL_VERSION,
|
||||
PROP_OS_PRETTY_NAME,
|
||||
PROP_OS_CPE_NAME,
|
||||
PROP_HOME_URL,
|
||||
@ -55,8 +52,6 @@ enum {
|
||||
typedef struct Context {
|
||||
char *data[_PROP_MAX];
|
||||
Hashmap *polkit_registry;
|
||||
sd_id128_t uuid;
|
||||
bool has_uuid;
|
||||
} Context;
|
||||
|
||||
static void context_reset(Context *c) {
|
||||
@ -68,7 +63,7 @@ static void context_reset(Context *c) {
|
||||
c->data[p] = mfree(c->data[p]);
|
||||
}
|
||||
|
||||
static void context_clear(Context *c) {
|
||||
static void context_destroy(Context *c) {
|
||||
assert(c);
|
||||
|
||||
context_reset(c);
|
||||
@ -77,20 +72,11 @@ static void context_clear(Context *c) {
|
||||
|
||||
static int context_read_data(Context *c) {
|
||||
int r;
|
||||
struct utsname u;
|
||||
|
||||
assert(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();
|
||||
if (!c->data[PROP_HOSTNAME])
|
||||
return -ENOMEM;
|
||||
@ -116,17 +102,6 @@ static int context_read_data(Context *c) {
|
||||
if (r < 0 && r != -ENOENT)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -411,6 +386,22 @@ static int property_get_chassis(
|
||||
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) {
|
||||
Context *c = userdata;
|
||||
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) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
Context *c = userdata;
|
||||
bool has_uuid = false;
|
||||
int interactive, r;
|
||||
sd_id128_t uuid;
|
||||
|
||||
assert(m);
|
||||
assert(c);
|
||||
|
||||
if (!c->has_uuid)
|
||||
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/class/dmi/id/product_uuid", ID128_UUID, &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);
|
||||
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)
|
||||
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)
|
||||
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("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("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, 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", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, 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", property_get_uname_field, offsetof(struct utsname, release), SD_BUS_VTABLE_ABSOLUTE_OFFSET|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("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),
|
||||
@ -780,7 +785,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
|
||||
}
|
||||
|
||||
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_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
int r;
|
||||
|
||||
@ -410,5 +410,5 @@ int open_journal_for_upload(Uploader *u,
|
||||
cursor);
|
||||
}
|
||||
|
||||
return process_journal_input(u, 1 + !!after_cursor);
|
||||
return process_journal_input(u, !!after_cursor);
|
||||
}
|
||||
|
||||
@ -253,7 +253,8 @@ static int dhcp6_client_set_duid_internal(
|
||||
r = dhcp_validate_duid_len(duid_type, duid_len, false);
|
||||
if (r < 0)
|
||||
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);
|
||||
|
||||
@ -99,6 +99,7 @@ static int acquire_user_record(
|
||||
|
||||
_cleanup_(user_record_unrefp) UserRecord *ur = NULL;
|
||||
const char *username = NULL, *json = NULL;
|
||||
_cleanup_free_ char *field = NULL;
|
||||
int r;
|
||||
|
||||
assert(handle);
|
||||
@ -114,39 +115,18 @@ static int acquire_user_record(
|
||||
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. */
|
||||
r = pam_get_data(handle, "systemd-user-record", (const void**) &json);
|
||||
if (r != PAM_SUCCESS || !json) {
|
||||
_cleanup_free_ char *formatted = NULL;
|
||||
field = strjoin("systemd-user-record-", username);
|
||||
if (!field)
|
||||
return pam_log_oom(handle);
|
||||
|
||||
r = pam_get_data(handle, field, (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;
|
||||
}
|
||||
|
||||
/* 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 {
|
||||
if (r == PAM_SUCCESS && json) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
|
||||
/* 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.");
|
||||
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)) {
|
||||
|
||||
@ -4,25 +4,11 @@
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "ipvlan.h"
|
||||
#include "ipvlan-util.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");
|
||||
|
||||
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");
|
||||
|
||||
static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
|
||||
|
||||
@ -4,24 +4,9 @@
|
||||
#include <netinet/in.h>
|
||||
#include <linux/if_link.h>
|
||||
|
||||
#include "ipvlan-util.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 {
|
||||
NetDev meta;
|
||||
|
||||
@ -34,12 +19,6 @@ DEFINE_NETDEV_CAST(IPVTAP, IPVlan);
|
||||
extern const NetDevVTable ipvlan_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_flags);
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
#include "geneve-util.h"
|
||||
#include "glob-util.h"
|
||||
#include "hwdb-util.h"
|
||||
#include "ipvlan-util.h"
|
||||
#include "local-addresses.h"
|
||||
#include "locale-util.h"
|
||||
#include "logs-show.h"
|
||||
@ -192,6 +193,10 @@ typedef struct LinkInfo {
|
||||
/* macvlan and macvtap info */
|
||||
uint32_t macvlan_mode;
|
||||
|
||||
/* ipvlan info */
|
||||
uint16_t ipvlan_mode;
|
||||
uint16_t ipvlan_flags;
|
||||
|
||||
/* ethtool info */
|
||||
int autonegotiation;
|
||||
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);
|
||||
} else if (STR_IN_SET(received_kind, "macvlan", "macvtap"))
|
||||
(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);
|
||||
|
||||
@ -1798,6 +1807,28 @@ static int link_status_one(
|
||||
TABLE_STRING, macvlan_mode_to_string(info->macvlan_mode));
|
||||
if (r < 0)
|
||||
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) {
|
||||
|
||||
@ -546,30 +546,47 @@ static int condition_test_capability(Condition *c, char **env) {
|
||||
}
|
||||
|
||||
static int condition_test_needs_update(Condition *c, char **env) {
|
||||
const char *p;
|
||||
struct stat usr, other;
|
||||
const char *p;
|
||||
bool b;
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
assert(c->parameter);
|
||||
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 (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;
|
||||
|
||||
/* Any other failure means we should allow the condition to be true,
|
||||
* so that we rather invoke too many update tools than too
|
||||
* few. */
|
||||
|
||||
if (!path_is_absolute(c->parameter))
|
||||
return true;
|
||||
/* Any other failure means we should allow the condition to be true, so that we rather invoke too
|
||||
* many update tools than too few. */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* (otherwise the filesystem supports nsec timestamps, see stat(2)).
|
||||
*/
|
||||
if (usr.st_mtim.tv_nsec > 0 && other.st_mtim.tv_nsec == 0) {
|
||||
_cleanup_free_ char *timestamp_str = NULL;
|
||||
uint64_t timestamp;
|
||||
int r;
|
||||
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;
|
||||
r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", ×tamp_str);
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
|
||||
uint64_t timestamp;
|
||||
r = safe_atou64(timestamp_str, ×tamp);
|
||||
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;
|
||||
}
|
||||
|
||||
timespec_store(&other.st_mtim, timestamp);
|
||||
}
|
||||
|
||||
return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
|
||||
return timespec_load_nsec(&usr.st_mtim) > timestamp;
|
||||
}
|
||||
|
||||
static int condition_test_first_boot(Condition *c, char **env) {
|
||||
int r;
|
||||
int r, q;
|
||||
bool b;
|
||||
|
||||
assert(c);
|
||||
assert(c->parameter);
|
||||
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);
|
||||
if (r < 0)
|
||||
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) {
|
||||
|
||||
22
src/shared/ipvlan-util.c
Normal file
22
src/shared/ipvlan-util.c
Normal 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
29
src/shared/ipvlan-util.h
Normal 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_;
|
||||
@ -120,6 +120,8 @@ shared_sources = files('''
|
||||
install-printf.h
|
||||
install.c
|
||||
install.h
|
||||
ipvlan-util.c
|
||||
ipvlan-util.h
|
||||
ip-protocol-list.c
|
||||
ip-protocol-list.h
|
||||
journal-importer.c
|
||||
|
||||
@ -24,15 +24,15 @@ units = [
|
||||
['hibernate.target', 'ENABLE_HIBERNATE'],
|
||||
['hybrid-sleep.target', 'ENABLE_HIBERNATE'],
|
||||
['suspend-then-hibernate.target', 'ENABLE_HIBERNATE'],
|
||||
['initrd-cleanup.service', ''],
|
||||
['initrd-fs.target', ''],
|
||||
['initrd-parse-etc.service', ''],
|
||||
['initrd-root-device.target', ''],
|
||||
['initrd-root-fs.target', ''],
|
||||
['initrd-switch-root.service', ''],
|
||||
['initrd-switch-root.target', ''],
|
||||
['initrd-udevadm-cleanup-db.service', ''],
|
||||
['initrd.target', ''],
|
||||
['initrd-cleanup.service', 'ENABLE_INITRD'],
|
||||
['initrd-fs.target', 'ENABLE_INITRD'],
|
||||
['initrd-parse-etc.service', 'ENABLE_INITRD'],
|
||||
['initrd-root-device.target', 'ENABLE_INITRD'],
|
||||
['initrd-root-fs.target', 'ENABLE_INITRD'],
|
||||
['initrd-switch-root.service', 'ENABLE_INITRD'],
|
||||
['initrd-switch-root.target', 'ENABLE_INITRD'],
|
||||
['initrd-udevadm-cleanup-db.service', 'ENABLE_INITRD'],
|
||||
['initrd.target', 'ENABLE_INITRD'],
|
||||
['kexec.target', ''],
|
||||
['ldconfig.service', 'ENABLE_LDCONFIG',
|
||||
'sysinit.target.wants/'],
|
||||
@ -225,7 +225,7 @@ in_units = [
|
||||
['systemd-user-sessions.service', 'HAVE_PAM',
|
||||
'multi-user.target.wants/'],
|
||||
['systemd-vconsole-setup.service', 'ENABLE_VCONSOLE'],
|
||||
['systemd-volatile-root.service', ''],
|
||||
['systemd-volatile-root.service', 'ENABLE_INITRD'],
|
||||
['systemd-repart.service', 'ENABLE_REPART',
|
||||
'sysinit.target.wants/ initrd-root-fs.target.wants/'],
|
||||
['user-runtime-dir@.service', ''],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user