Compare commits
9 Commits
1cdc42f283
...
a1ba8c5b71
Author | SHA1 | Date |
---|---|---|
Jay Burger | a1ba8c5b71 | |
Lennart Poettering | 7bf6babfa2 | |
Lennart Poettering | bc8d57f290 | |
Christian Göttsche | 3d9fbea43e | |
Christian Göttsche | a9ba0e328f | |
Christian Göttsche | a11bfc17dc | |
Lennart Poettering | 037b0a47b0 | |
Lennart Poettering | 6e78726e20 | |
Lennart Poettering | 88d775b734 |
|
@ -1660,7 +1660,7 @@ test_dlopen = executable(
|
||||||
build_by_default : want_tests != 'false')
|
build_by_default : want_tests != 'false')
|
||||||
|
|
||||||
foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
|
foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
|
||||||
['systemd', 'ENABLE_NSS_SYSTEMD', 'src/nss-systemd/userdb-glue.c src/nss-systemd/userdb-glue.h'],
|
['systemd', 'ENABLE_NSS_SYSTEMD', 'src/nss-systemd/userdb-glue.c src/nss-systemd/userdb-glue.h src/nss-systemd/nss-systemd.h'],
|
||||||
['mymachines', 'ENABLE_NSS_MYMACHINES'],
|
['mymachines', 'ENABLE_NSS_MYMACHINES'],
|
||||||
['resolve', 'ENABLE_NSS_RESOLVE']]
|
['resolve', 'ENABLE_NSS_RESOLVE']]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include "macro.h"
|
||||||
|
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC(void*, dlclose);
|
|
@ -39,6 +39,7 @@ basic_sources = files('''
|
||||||
device-nodes.h
|
device-nodes.h
|
||||||
dirent-util.c
|
dirent-util.c
|
||||||
dirent-util.h
|
dirent-util.h
|
||||||
|
dlfcn-util.h
|
||||||
efivars.c
|
efivars.c
|
||||||
efivars.h
|
efivars.h
|
||||||
env-file.c
|
env-file.c
|
||||||
|
@ -328,7 +329,8 @@ libbasic = static_library(
|
||||||
threads,
|
threads,
|
||||||
libcap,
|
libcap,
|
||||||
libselinux,
|
libselinux,
|
||||||
libm],
|
libm,
|
||||||
|
libdl],
|
||||||
c_args : ['-fvisibility=default'],
|
c_args : ['-fvisibility=default'],
|
||||||
install : false)
|
install : false)
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@ int mac_selinux_init(void) {
|
||||||
|
|
||||||
label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
|
label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
|
||||||
if (!label_hnd)
|
if (!label_hnd)
|
||||||
return log_enforcing_errno(errno, "Failed to initialize SELinux context: %m");
|
return log_enforcing_errno(errno, "Failed to initialize SELinux labeling handle: %m");
|
||||||
|
|
||||||
after_timestamp = now(CLOCK_MONOTONIC);
|
after_timestamp = now(CLOCK_MONOTONIC);
|
||||||
after_mallinfo = mallinfo();
|
after_mallinfo = mallinfo();
|
||||||
|
@ -376,13 +376,9 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
|
||||||
char* mac_selinux_free(char *label) {
|
char* mac_selinux_free(char *label) {
|
||||||
|
|
||||||
#if HAVE_SELINUX
|
#if HAVE_SELINUX
|
||||||
if (!label)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!mac_selinux_use())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
freecon(label);
|
freecon(label);
|
||||||
|
#else
|
||||||
|
assert(!label);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -12,6 +12,18 @@
|
||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
#include "virt.h"
|
#include "virt.h"
|
||||||
|
|
||||||
|
static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
|
||||||
|
[EMERGENCY_ACTION_NONE] = "none",
|
||||||
|
[EMERGENCY_ACTION_REBOOT] = "reboot",
|
||||||
|
[EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force",
|
||||||
|
[EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
|
||||||
|
[EMERGENCY_ACTION_POWEROFF] = "poweroff",
|
||||||
|
[EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force",
|
||||||
|
[EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate",
|
||||||
|
[EMERGENCY_ACTION_EXIT] = "exit",
|
||||||
|
[EMERGENCY_ACTION_EXIT_FORCE] = "exit-force",
|
||||||
|
};
|
||||||
|
|
||||||
static void log_and_status(Manager *m, bool warn, const char *message, const char *reason) {
|
static void log_and_status(Manager *m, bool warn, const char *message, const char *reason) {
|
||||||
log_full(warn ? LOG_WARNING : LOG_DEBUG, "%s: %s", message, reason);
|
log_full(warn ? LOG_WARNING : LOG_DEBUG, "%s: %s", message, reason);
|
||||||
if (warn)
|
if (warn)
|
||||||
|
@ -28,10 +40,22 @@ void emergency_action(
|
||||||
int exit_status,
|
int exit_status,
|
||||||
const char *reason) {
|
const char *reason) {
|
||||||
|
|
||||||
|
Unit *u;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(action >= 0);
|
assert(action >= 0);
|
||||||
assert(action < _EMERGENCY_ACTION_MAX);
|
assert(action < _EMERGENCY_ACTION_MAX);
|
||||||
|
|
||||||
|
/* Is the special shutdown target active or queued? If so, we are in shutdown state */
|
||||||
|
if (IN_SET(action, EMERGENCY_ACTION_REBOOT, EMERGENCY_ACTION_POWEROFF, EMERGENCY_ACTION_EXIT)) {
|
||||||
|
u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
|
||||||
|
if (u && unit_active_or_pending(u)) {
|
||||||
|
log_notice("Shutdown is already active. Skipping emergency action request %s.",
|
||||||
|
emergency_action_table[action]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (action == EMERGENCY_ACTION_NONE)
|
if (action == EMERGENCY_ACTION_NONE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -126,17 +150,6 @@ void emergency_action(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
|
|
||||||
[EMERGENCY_ACTION_NONE] = "none",
|
|
||||||
[EMERGENCY_ACTION_REBOOT] = "reboot",
|
|
||||||
[EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force",
|
|
||||||
[EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
|
|
||||||
[EMERGENCY_ACTION_POWEROFF] = "poweroff",
|
|
||||||
[EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force",
|
|
||||||
[EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate",
|
|
||||||
[EMERGENCY_ACTION_EXIT] = "exit",
|
|
||||||
[EMERGENCY_ACTION_EXIT_FORCE] = "exit-force",
|
|
||||||
};
|
|
||||||
DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction);
|
DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction);
|
||||||
|
|
||||||
int parse_emergency_action(
|
int parse_emergency_action(
|
||||||
|
|
|
@ -2559,7 +2559,7 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mac_selinux_init() < 0) {
|
if (mac_selinux_init() < 0) {
|
||||||
error_message = "Failed to initialize SELinux policy";
|
error_message = "Failed to initialize SELinux support";
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2603,6 +2603,11 @@ int main(int argc, char *argv[]) {
|
||||||
/* clear the kernel timestamp,
|
/* clear the kernel timestamp,
|
||||||
* because we are not PID 1 */
|
* because we are not PID 1 */
|
||||||
kernel_timestamp = DUAL_TIMESTAMP_NULL;
|
kernel_timestamp = DUAL_TIMESTAMP_NULL;
|
||||||
|
|
||||||
|
if (mac_selinux_init() < 0) {
|
||||||
|
error_message = "Failed to initialize SELinux support";
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg_system) {
|
if (arg_system) {
|
||||||
|
|
|
@ -801,7 +801,10 @@ static int run(int argc, char *argv[]) {
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
umask(0022);
|
umask(0022);
|
||||||
mac_selinux_init();
|
|
||||||
|
r = mac_selinux_init();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,9 @@ static int run(int argc, char *argv[]) {
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
mac_selinux_init();
|
r = mac_selinux_init();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
return hwdb_main(argc, argv);
|
return hwdb_main(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "bus-message.h"
|
#include "bus-message.h"
|
||||||
#include "bus-polkit.h"
|
#include "bus-polkit.h"
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
|
#include "dlfcn-util.h"
|
||||||
#include "keymap-util.h"
|
#include "keymap-util.h"
|
||||||
#include "locale-util.h"
|
#include "locale-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
@ -530,7 +531,7 @@ static int verify_xkb_rmlvo(const char *model, const char *layout, const char *v
|
||||||
};
|
};
|
||||||
struct xkb_context *ctx = NULL;
|
struct xkb_context *ctx = NULL;
|
||||||
struct xkb_keymap *km = NULL;
|
struct xkb_keymap *km = NULL;
|
||||||
void *dl;
|
_cleanup_(dlclosep) void *dl = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* Compile keymap from RMLVO information to check out its validity */
|
/* Compile keymap from RMLVO information to check out its validity */
|
||||||
|
@ -582,7 +583,6 @@ finish:
|
||||||
if (symbol_xkb_context_unref && ctx)
|
if (symbol_xkb_context_unref && ctx)
|
||||||
symbol_xkb_context_unref(ctx);
|
symbol_xkb_context_unref(ctx);
|
||||||
|
|
||||||
(void) dlclose(dl);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,7 +788,10 @@ static int run(int argc, char *argv[]) {
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
umask(0022);
|
umask(0022);
|
||||||
mac_selinux_init();
|
|
||||||
|
r = mac_selinux_init();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
|
||||||
|
|
||||||
|
|
|
@ -34,5 +34,5 @@ tests += [
|
||||||
'src/locale/keymap-util.c',
|
'src/locale/keymap-util.c',
|
||||||
'src/locale/keymap-util.h'],
|
'src/locale/keymap-util.h'],
|
||||||
[libshared],
|
[libshared],
|
||||||
[libdl]],
|
[]],
|
||||||
]
|
]
|
||||||
|
|
|
@ -1173,7 +1173,7 @@ static int run(int argc, char *argv[]) {
|
||||||
|
|
||||||
r = mac_selinux_init();
|
r = mac_selinux_init();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Could not initialize labelling: %m");
|
return r;
|
||||||
|
|
||||||
/* Always create the directories people can create inotify watches in. Note that some applications might check
|
/* Always create the directories people can create inotify watches in. Note that some applications might check
|
||||||
* for the existence of /run/systemd/seats/ to determine whether logind is available, so please always make
|
* for the existence of /run/systemd/seats/ to determine whether logind is available, so please always make
|
||||||
|
|
|
@ -192,11 +192,11 @@ static int run(int argc, char *argv[]) {
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"First argument must be either \"start\" or \"stop\".");
|
"First argument must be either \"start\" or \"stop\".");
|
||||||
|
|
||||||
|
umask(0022);
|
||||||
|
|
||||||
r = mac_selinux_init();
|
r = mac_selinux_init();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Could not initialize labelling: %m\n");
|
return r;
|
||||||
|
|
||||||
umask(0022);
|
|
||||||
|
|
||||||
if (streq(argv[1], "start"))
|
if (streq(argv[1], "start"))
|
||||||
return do_mount(argv[2]);
|
return do_mount(argv[2]);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "group-record-nss.h"
|
#include "group-record-nss.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "nss-systemd.h"
|
||||||
#include "nss-util.h"
|
#include "nss-util.h"
|
||||||
#include "pthread-util.h"
|
#include "pthread-util.h"
|
||||||
#include "signal-util.h"
|
#include "signal-util.h"
|
||||||
|
@ -299,7 +300,7 @@ enum nss_status _nss_systemd_setpwent(int stayopen) {
|
||||||
PROTECT_ERRNO;
|
PROTECT_ERRNO;
|
||||||
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
|
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
|
||||||
|
|
||||||
if (userdb_nss_compat_is_enabled() <= 0)
|
if (_nss_systemd_is_blocked())
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
|
|
||||||
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
|
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
|
||||||
|
@ -323,7 +324,7 @@ enum nss_status _nss_systemd_setgrent(int stayopen) {
|
||||||
PROTECT_ERRNO;
|
PROTECT_ERRNO;
|
||||||
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
|
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
|
||||||
|
|
||||||
if (userdb_nss_compat_is_enabled() <= 0)
|
if (_nss_systemd_is_blocked())
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
|
|
||||||
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
|
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
|
||||||
|
@ -353,13 +354,7 @@ enum nss_status _nss_systemd_getpwent_r(
|
||||||
assert(result);
|
assert(result);
|
||||||
assert(errnop);
|
assert(errnop);
|
||||||
|
|
||||||
r = userdb_nss_compat_is_enabled();
|
if (_nss_systemd_is_blocked())
|
||||||
if (r < 0) {
|
|
||||||
UNPROTECT_ERRNO;
|
|
||||||
*errnop = -r;
|
|
||||||
return NSS_STATUS_UNAVAIL;
|
|
||||||
}
|
|
||||||
if (!r)
|
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
|
|
||||||
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
|
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
|
||||||
|
@ -406,14 +401,8 @@ enum nss_status _nss_systemd_getgrent_r(
|
||||||
assert(result);
|
assert(result);
|
||||||
assert(errnop);
|
assert(errnop);
|
||||||
|
|
||||||
r = userdb_nss_compat_is_enabled();
|
if (_nss_systemd_is_blocked())
|
||||||
if (r < 0) {
|
return NSS_STATUS_NOTFOUND;
|
||||||
UNPROTECT_ERRNO;
|
|
||||||
*errnop = -r;
|
|
||||||
return NSS_STATUS_UNAVAIL;
|
|
||||||
}
|
|
||||||
if (!r)
|
|
||||||
return NSS_STATUS_UNAVAIL;
|
|
||||||
|
|
||||||
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
|
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
|
||||||
|
|
||||||
|
@ -459,7 +448,7 @@ enum nss_status _nss_systemd_getgrent_r(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getgrent_data.by_membership) {
|
if (getgrent_data.by_membership) {
|
||||||
_cleanup_close_ int lock_fd = -1;
|
_cleanup_(_nss_systemd_unblockp) bool blocked = false;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
_cleanup_free_ char *user_name = NULL, *group_name = NULL;
|
_cleanup_free_ char *user_name = NULL, *group_name = NULL;
|
||||||
|
@ -479,13 +468,15 @@ enum nss_status _nss_systemd_getgrent_r(
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* We are about to recursively call into NSS, let's make sure we disable recursion into our own code. */
|
/* We are about to recursively call into NSS, let's make sure we disable recursion into our own code. */
|
||||||
if (lock_fd < 0) {
|
if (!blocked) {
|
||||||
lock_fd = userdb_nss_compat_disable();
|
r = _nss_systemd_block(true);
|
||||||
if (lock_fd < 0 && lock_fd != -EBUSY) {
|
if (r < 0) {
|
||||||
UNPROTECT_ERRNO;
|
UNPROTECT_ERRNO;
|
||||||
*errnop = -lock_fd;
|
*errnop = -r;
|
||||||
return NSS_STATUS_UNAVAIL;
|
return NSS_STATUS_UNAVAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blocked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = nss_group_record_by_name(group_name, false, &gr);
|
r = nss_group_record_by_name(group_name, false, &gr);
|
||||||
|
@ -549,13 +540,7 @@ enum nss_status _nss_systemd_initgroups_dyn(
|
||||||
if (STR_IN_SET(user_name, root_passwd.pw_name, nobody_passwd.pw_name))
|
if (STR_IN_SET(user_name, root_passwd.pw_name, nobody_passwd.pw_name))
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
|
|
||||||
r = userdb_nss_compat_is_enabled();
|
if (_nss_systemd_is_blocked())
|
||||||
if (r < 0) {
|
|
||||||
UNPROTECT_ERRNO;
|
|
||||||
*errnop = -r;
|
|
||||||
return NSS_STATUS_UNAVAIL;
|
|
||||||
}
|
|
||||||
if (!r)
|
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
|
|
||||||
r = membershipdb_by_user(user_name, nss_glue_userdb_flags(), &iterator);
|
r = membershipdb_by_user(user_name, nss_glue_userdb_flags(), &iterator);
|
||||||
|
@ -581,7 +566,7 @@ enum nss_status _nss_systemd_initgroups_dyn(
|
||||||
/* The group might be defined via traditional NSS only, hence let's do a full look-up without
|
/* The group might be defined via traditional NSS only, hence let's do a full look-up without
|
||||||
* disabling NSS. This means we are operating recursively here. */
|
* disabling NSS. This means we are operating recursively here. */
|
||||||
|
|
||||||
r = groupdb_by_name(group_name, nss_glue_userdb_flags() & ~USERDB_AVOID_NSS, &g);
|
r = groupdb_by_name(group_name, (nss_glue_userdb_flags() & ~USERDB_AVOID_NSS) | USERDB_AVOID_SHADOW, &g);
|
||||||
if (r == -ESRCH)
|
if (r == -ESRCH)
|
||||||
continue;
|
continue;
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
|
@ -627,3 +612,29 @@ enum nss_status _nss_systemd_initgroups_dyn(
|
||||||
|
|
||||||
return any ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND;
|
return any ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static thread_local unsigned _blocked = 0;
|
||||||
|
|
||||||
|
_public_ int _nss_systemd_block(bool b) {
|
||||||
|
|
||||||
|
/* This blocks recursively: it's blocked for as many times this function is called with `true` until
|
||||||
|
* it is called an equal time with `false`. */
|
||||||
|
|
||||||
|
if (b) {
|
||||||
|
if (_blocked >= UINT_MAX)
|
||||||
|
return -EOVERFLOW;
|
||||||
|
|
||||||
|
_blocked++;
|
||||||
|
} else {
|
||||||
|
if (_blocked <= 0)
|
||||||
|
return -EOVERFLOW;
|
||||||
|
|
||||||
|
_blocked--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b; /* Return what is passed in, i.e. the new state from the PoV of the caller */
|
||||||
|
}
|
||||||
|
|
||||||
|
_public_ bool _nss_systemd_is_blocked(void) {
|
||||||
|
return _blocked > 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
int _nss_systemd_block(bool b);
|
||||||
|
bool _nss_systemd_is_blocked(void);
|
||||||
|
|
||||||
|
/* For use with the _cleanup_() macro */
|
||||||
|
static inline void _nss_systemd_unblockp(bool *b) {
|
||||||
|
if (*b)
|
||||||
|
assert_se(_nss_systemd_block(false) >= 0);
|
||||||
|
}
|
|
@ -20,5 +20,9 @@ global:
|
||||||
_nss_systemd_setgrent;
|
_nss_systemd_setgrent;
|
||||||
_nss_systemd_getgrent_r;
|
_nss_systemd_getgrent_r;
|
||||||
_nss_systemd_initgroups_dyn;
|
_nss_systemd_initgroups_dyn;
|
||||||
|
|
||||||
|
/* These two are not used by glibc, but can be used by apps to explicitly disable nss-systemd for the calling thread. */
|
||||||
|
_nss_systemd_block;
|
||||||
|
_nss_systemd_is_blocked;
|
||||||
local: *;
|
local: *;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "env-util.h"
|
#include "env-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "group-record-nss.h"
|
#include "group-record-nss.h"
|
||||||
|
#include "nss-systemd.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "user-record.h"
|
#include "user-record.h"
|
||||||
#include "userdb-glue.h"
|
#include "userdb-glue.h"
|
||||||
|
@ -74,12 +75,7 @@ enum nss_status userdb_getpwnam(
|
||||||
assert(pwd);
|
assert(pwd);
|
||||||
assert(errnop);
|
assert(errnop);
|
||||||
|
|
||||||
r = userdb_nss_compat_is_enabled();
|
if (_nss_systemd_is_blocked())
|
||||||
if (r < 0) {
|
|
||||||
*errnop = -r;
|
|
||||||
return NSS_STATUS_UNAVAIL;
|
|
||||||
}
|
|
||||||
if (!r)
|
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
|
|
||||||
r = userdb_by_name(name, nss_glue_userdb_flags(), &hr);
|
r = userdb_by_name(name, nss_glue_userdb_flags(), &hr);
|
||||||
|
@ -112,12 +108,7 @@ enum nss_status userdb_getpwuid(
|
||||||
assert(pwd);
|
assert(pwd);
|
||||||
assert(errnop);
|
assert(errnop);
|
||||||
|
|
||||||
r = userdb_nss_compat_is_enabled();
|
if (_nss_systemd_is_blocked())
|
||||||
if (r < 0) {
|
|
||||||
*errnop = -r;
|
|
||||||
return NSS_STATUS_UNAVAIL;
|
|
||||||
}
|
|
||||||
if (!r)
|
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
|
|
||||||
r = userdb_by_uid(uid, nss_glue_userdb_flags(), &hr);
|
r = userdb_by_uid(uid, nss_glue_userdb_flags(), &hr);
|
||||||
|
@ -214,12 +205,7 @@ enum nss_status userdb_getgrnam(
|
||||||
assert(gr);
|
assert(gr);
|
||||||
assert(errnop);
|
assert(errnop);
|
||||||
|
|
||||||
r = userdb_nss_compat_is_enabled();
|
if (_nss_systemd_is_blocked())
|
||||||
if (r < 0) {
|
|
||||||
*errnop = -r;
|
|
||||||
return NSS_STATUS_UNAVAIL;
|
|
||||||
}
|
|
||||||
if (!r)
|
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
|
|
||||||
r = groupdb_by_name(name, nss_glue_userdb_flags(), &g);
|
r = groupdb_by_name(name, nss_glue_userdb_flags(), &g);
|
||||||
|
@ -235,7 +221,7 @@ enum nss_status userdb_getgrnam(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g) {
|
if (!g) {
|
||||||
_cleanup_close_ int lock_fd = -1;
|
_cleanup_(_nss_systemd_unblockp) bool blocked = false;
|
||||||
|
|
||||||
if (strv_isempty(members))
|
if (strv_isempty(members))
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
|
@ -245,11 +231,13 @@ enum nss_status userdb_getgrnam(
|
||||||
* acquire it, so that we can extend it (that's because glibc's group merging feature will
|
* acquire it, so that we can extend it (that's because glibc's group merging feature will
|
||||||
* merge groups only if both GID and name match and thus we need to have both first). It
|
* merge groups only if both GID and name match and thus we need to have both first). It
|
||||||
* sucks behaving recursively likely this, but it's apparently what everybody does. We break
|
* sucks behaving recursively likely this, but it's apparently what everybody does. We break
|
||||||
* the recursion for ourselves via the userdb_nss_compat_disable() lock. */
|
* the recursion for ourselves via the _nss_systemd_block_nss() lock. */
|
||||||
|
|
||||||
lock_fd = userdb_nss_compat_disable();
|
r = _nss_systemd_block(true);
|
||||||
if (lock_fd < 0 && lock_fd != -EBUSY)
|
if (r < 0)
|
||||||
return lock_fd;
|
return r;
|
||||||
|
|
||||||
|
blocked = true;
|
||||||
|
|
||||||
r = nss_group_record_by_name(name, false, &g);
|
r = nss_group_record_by_name(name, false, &g);
|
||||||
if (r == -ESRCH)
|
if (r == -ESRCH)
|
||||||
|
@ -285,12 +273,7 @@ enum nss_status userdb_getgrgid(
|
||||||
assert(gr);
|
assert(gr);
|
||||||
assert(errnop);
|
assert(errnop);
|
||||||
|
|
||||||
r = userdb_nss_compat_is_enabled();
|
if (_nss_systemd_is_blocked())
|
||||||
if (r < 0) {
|
|
||||||
*errnop = -r;
|
|
||||||
return NSS_STATUS_UNAVAIL;
|
|
||||||
}
|
|
||||||
if (!r)
|
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
|
|
||||||
r = groupdb_by_gid(gid, nss_glue_userdb_flags(), &g);
|
r = groupdb_by_gid(gid, nss_glue_userdb_flags(), &g);
|
||||||
|
@ -300,20 +283,21 @@ enum nss_status userdb_getgrgid(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g) {
|
if (!g) {
|
||||||
_cleanup_close_ int lock_fd = -1;
|
_cleanup_(_nss_systemd_unblockp) bool blocked = false;
|
||||||
|
|
||||||
/* So, quite possibly we have to extend an existing group record with additional members. But
|
/* So, quite possibly we have to extend an existing group record with additional members. But
|
||||||
* to do this we need to know the group name first. The group didn't exist via non-NSS
|
* to do this we need to know the group name first. The group didn't exist via non-NSS
|
||||||
* queries though, hence let's try to acquire it here recursively via NSS. */
|
* queries though, hence let's try to acquire it here recursively via NSS. */
|
||||||
|
|
||||||
lock_fd = userdb_nss_compat_disable();
|
r = _nss_systemd_block(true);
|
||||||
if (lock_fd < 0 && lock_fd != -EBUSY)
|
if (r < 0)
|
||||||
return lock_fd;
|
return r;
|
||||||
|
|
||||||
|
blocked = true;
|
||||||
|
|
||||||
r = nss_group_record_by_gid(gid, false, &g);
|
r = nss_group_record_by_gid(gid, false, &g);
|
||||||
if (r == -ESRCH)
|
if (r == -ESRCH)
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
*errnop = -r;
|
*errnop = -r;
|
||||||
return NSS_STATUS_UNAVAIL;
|
return NSS_STATUS_UNAVAIL;
|
||||||
|
|
|
@ -40,7 +40,7 @@ static int run(int argc, char *argv[]) {
|
||||||
|
|
||||||
r = mac_selinux_init();
|
r = mac_selinux_init();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "SELinux setup failed: %m");
|
return r;
|
||||||
|
|
||||||
/* Drop privileges, but only if we have been started as root. If we are not running as root we assume most
|
/* Drop privileges, but only if we have been started as root. If we are not running as root we assume most
|
||||||
* privileges are already dropped and we can't create our directory. */
|
* privileges are already dropped and we can't create our directory. */
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <sys/auxv.h>
|
#include <sys/auxv.h>
|
||||||
|
|
||||||
#include "dirent-util.h"
|
#include "dirent-util.h"
|
||||||
|
#include "dlfcn-util.h"
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "group-record-nss.h"
|
#include "group-record-nss.h"
|
||||||
|
@ -32,8 +33,8 @@ struct UserDBIterator {
|
||||||
bool nss_iterating:1;
|
bool nss_iterating:1;
|
||||||
bool synthesize_root:1;
|
bool synthesize_root:1;
|
||||||
bool synthesize_nobody:1;
|
bool synthesize_nobody:1;
|
||||||
|
bool nss_systemd_blocked:1;
|
||||||
int error;
|
int error;
|
||||||
int nss_lock;
|
|
||||||
unsigned n_found;
|
unsigned n_found;
|
||||||
sd_event *event;
|
sd_event *event;
|
||||||
UserRecord *found_user; /* when .what == LOOKUP_USER */
|
UserRecord *found_user; /* when .what == LOOKUP_USER */
|
||||||
|
@ -85,7 +86,9 @@ UserDBIterator* userdb_iterator_free(UserDBIterator *iterator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sd_event_unref(iterator->event);
|
sd_event_unref(iterator->event);
|
||||||
safe_close(iterator->nss_lock);
|
|
||||||
|
if (iterator->nss_systemd_blocked)
|
||||||
|
assert_se(userdb_block_nss_systemd(false) >= 0);
|
||||||
|
|
||||||
return mfree(iterator);
|
return mfree(iterator);
|
||||||
}
|
}
|
||||||
|
@ -102,12 +105,27 @@ static UserDBIterator* userdb_iterator_new(LookupWhat what) {
|
||||||
|
|
||||||
*i = (UserDBIterator) {
|
*i = (UserDBIterator) {
|
||||||
.what = what,
|
.what = what,
|
||||||
.nss_lock = -1,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int userdb_iterator_block_nss_systemd(UserDBIterator *iterator) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(iterator);
|
||||||
|
|
||||||
|
if (iterator->nss_systemd_blocked)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = userdb_block_nss_systemd(true);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
iterator->nss_systemd_blocked = true;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
struct user_group_data {
|
struct user_group_data {
|
||||||
JsonVariant *record;
|
JsonVariant *record;
|
||||||
bool incomplete;
|
bool incomplete;
|
||||||
|
@ -606,13 +624,11 @@ int userdb_by_name(const char *name, UserDBFlags flags, UserRecord **ret) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
|
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !iterator->nss_covered) {
|
||||||
/* Make sure the NSS lookup doesn't recurse back to us. (EBUSY is fine here, it just means we
|
/* Make sure the NSS lookup doesn't recurse back to us. */
|
||||||
* already took the lock from our thread, which is totally OK.) */
|
|
||||||
r = userdb_nss_compat_disable();
|
|
||||||
if (r >= 0 || r == -EBUSY) {
|
|
||||||
iterator->nss_lock = r;
|
|
||||||
|
|
||||||
|
r = userdb_iterator_block_nss_systemd(iterator);
|
||||||
|
if (r >= 0) {
|
||||||
/* Client-side NSS fallback */
|
/* Client-side NSS fallback */
|
||||||
r = nss_user_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
|
r = nss_user_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
|
@ -655,11 +671,9 @@ int userdb_by_uid(uid_t uid, UserDBFlags flags, UserRecord **ret) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
|
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !iterator->nss_covered) {
|
||||||
r = userdb_nss_compat_disable();
|
r = userdb_iterator_block_nss_systemd(iterator);
|
||||||
if (r >= 0 || r == -EBUSY) {
|
if (r >= 0) {
|
||||||
iterator->nss_lock = r;
|
|
||||||
|
|
||||||
/* Client-side NSS fallback */
|
/* Client-side NSS fallback */
|
||||||
r = nss_user_record_by_uid(uid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
|
r = nss_user_record_by_uid(uid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
|
@ -693,9 +707,9 @@ int userdb_all(UserDBFlags flags, UserDBIterator **ret) {
|
||||||
r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetUserRecord", true, NULL, flags);
|
r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetUserRecord", true, NULL, flags);
|
||||||
|
|
||||||
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) {
|
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) {
|
||||||
iterator->nss_lock = userdb_nss_compat_disable();
|
r = userdb_iterator_block_nss_systemd(iterator);
|
||||||
if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
|
if (r < 0)
|
||||||
return iterator->nss_lock;
|
return r;
|
||||||
|
|
||||||
setpwent();
|
setpwent();
|
||||||
iterator->nss_iterating = true;
|
iterator->nss_iterating = true;
|
||||||
|
@ -815,10 +829,8 @@ int groupdb_by_name(const char *name, UserDBFlags flags, GroupRecord **ret) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
|
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
|
||||||
r = userdb_nss_compat_disable();
|
r = userdb_iterator_block_nss_systemd(iterator);
|
||||||
if (r >= 0 || r == -EBUSY) {
|
if (r >= 0) {
|
||||||
iterator->nss_lock = r;
|
|
||||||
|
|
||||||
r = nss_group_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
|
r = nss_group_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -861,10 +873,8 @@ int groupdb_by_gid(gid_t gid, UserDBFlags flags, GroupRecord **ret) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
|
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
|
||||||
r = userdb_nss_compat_disable();
|
r = userdb_iterator_block_nss_systemd(iterator);
|
||||||
if (r >= 0 || r == -EBUSY) {
|
if (r >= 0) {
|
||||||
iterator->nss_lock = r;
|
|
||||||
|
|
||||||
r = nss_group_record_by_gid(gid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
|
r = nss_group_record_by_gid(gid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -897,9 +907,9 @@ int groupdb_all(UserDBFlags flags, UserDBIterator **ret) {
|
||||||
r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetGroupRecord", true, NULL, flags);
|
r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetGroupRecord", true, NULL, flags);
|
||||||
|
|
||||||
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) {
|
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) {
|
||||||
iterator->nss_lock = userdb_nss_compat_disable();
|
r = userdb_iterator_block_nss_systemd(iterator);
|
||||||
if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
|
if (r < 0)
|
||||||
return iterator->nss_lock;
|
return r;
|
||||||
|
|
||||||
setgrent();
|
setgrent();
|
||||||
iterator->nss_iterating = true;
|
iterator->nss_iterating = true;
|
||||||
|
@ -998,9 +1008,9 @@ int membershipdb_by_user(const char *name, UserDBFlags flags, UserDBIterator **r
|
||||||
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
|
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
iterator->nss_lock = userdb_nss_compat_disable();
|
r = userdb_iterator_block_nss_systemd(iterator);
|
||||||
if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
|
if (r < 0)
|
||||||
return iterator->nss_lock;
|
return r;
|
||||||
|
|
||||||
iterator->filter_user_name = strdup(name);
|
iterator->filter_user_name = strdup(name);
|
||||||
if (!iterator->filter_user_name)
|
if (!iterator->filter_user_name)
|
||||||
|
@ -1041,9 +1051,9 @@ int membershipdb_by_group(const char *name, UserDBFlags flags, UserDBIterator **
|
||||||
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
|
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
iterator->nss_lock = userdb_nss_compat_disable();
|
r = userdb_iterator_block_nss_systemd(iterator);
|
||||||
if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
|
if (r < 0)
|
||||||
return iterator->nss_lock;
|
return r;
|
||||||
|
|
||||||
/* We ignore all errors here, since the group might be defined by a userdb native service, and we queried them already above. */
|
/* We ignore all errors here, since the group might be defined by a userdb native service, and we queried them already above. */
|
||||||
(void) nss_group_record_by_name(name, false, &gr);
|
(void) nss_group_record_by_name(name, false, &gr);
|
||||||
|
@ -1082,9 +1092,9 @@ int membershipdb_all(UserDBFlags flags, UserDBIterator **ret) {
|
||||||
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
|
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
iterator->nss_lock = userdb_nss_compat_disable();
|
r = userdb_iterator_block_nss_systemd(iterator);
|
||||||
if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
|
if (r < 0)
|
||||||
return iterator->nss_lock;
|
return r;
|
||||||
|
|
||||||
setgrent();
|
setgrent();
|
||||||
iterator->nss_iterating = true;
|
iterator->nss_iterating = true;
|
||||||
|
@ -1221,115 +1231,24 @@ int membershipdb_by_group_strv(const char *name, UserDBFlags flags, char ***ret)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int userdb_thread_sockaddr(struct sockaddr_un *ret_sa, socklen_t *ret_salen) {
|
int userdb_block_nss_systemd(int b) {
|
||||||
static const uint8_t
|
_cleanup_(dlclosep) void *dl = NULL;
|
||||||
k1[16] = { 0x35, 0xc1, 0x1f, 0x41, 0x59, 0xc6, 0xa0, 0xf9, 0x33, 0x4b, 0x17, 0x3d, 0xb9, 0xf6, 0x14, 0xd9 },
|
int (*call)(bool b);
|
||||||
k2[16] = { 0x6a, 0x11, 0x4c, 0x37, 0xe5, 0xa3, 0x8c, 0xa6, 0x93, 0x55, 0x64, 0x8c, 0x93, 0xee, 0xa1, 0x7b };
|
|
||||||
|
|
||||||
struct siphash sh;
|
/* Note that we might be called from libnss_systemd.so.2 itself, but that should be fine, really. */
|
||||||
uint64_t x, y;
|
|
||||||
pid_t tid;
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
assert(ret_sa);
|
|
||||||
assert(ret_salen);
|
|
||||||
|
|
||||||
/* This calculates an AF_UNIX socket address in the abstract namespace whose existence works as an
|
|
||||||
* indicator whether to emulate NSS records for complex user records that are also available via the
|
|
||||||
* varlink protocol. The name of the socket is picked in a way so that:
|
|
||||||
*
|
|
||||||
* → it is per-thread (by hashing from the TID)
|
|
||||||
*
|
|
||||||
* → is not guessable for foreign processes (by hashing from the — hopefully secret — AT_RANDOM
|
|
||||||
* value every process gets passed from the kernel
|
|
||||||
*
|
|
||||||
* By using a socket the NSS emulation can be nicely turned off for limited amounts of time only,
|
|
||||||
* simply controlled by the lifetime of the fd itself. By using an AF_UNIX socket in the abstract
|
|
||||||
* namespace the lock is automatically cleaned up when the process dies abnormally.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
p = ULONG_TO_PTR(getauxval(AT_RANDOM));
|
|
||||||
if (!p)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
tid = gettid();
|
|
||||||
|
|
||||||
siphash24_init(&sh, k1);
|
|
||||||
siphash24_compress(p, 16, &sh);
|
|
||||||
siphash24_compress(&tid, sizeof(tid), &sh);
|
|
||||||
x = siphash24_finalize(&sh);
|
|
||||||
|
|
||||||
siphash24_init(&sh, k2);
|
|
||||||
siphash24_compress(p, 16, &sh);
|
|
||||||
siphash24_compress(&tid, sizeof(tid), &sh);
|
|
||||||
y = siphash24_finalize(&sh);
|
|
||||||
|
|
||||||
*ret_sa = (struct sockaddr_un) {
|
|
||||||
.sun_family = AF_UNIX,
|
|
||||||
};
|
|
||||||
|
|
||||||
sprintf(ret_sa->sun_path + 1, "userdb-%016" PRIx64 "%016" PRIx64, x, y);
|
|
||||||
*ret_salen = offsetof(struct sockaddr_un, sun_path) + 1 + 7 + 32;
|
|
||||||
|
|
||||||
|
dl = dlopen(ROOTLIBDIR "libnss_systemd.so.2", RTLD_LAZY|RTLD_NODELETE);
|
||||||
|
if (!dl) {
|
||||||
|
/* If the file isn't installed, don't complain loudly */
|
||||||
|
log_debug("Failed to dlopen(libnss_systemd.so.2), ignoring: %s", dlerror());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int userdb_nss_compat_is_enabled(void) {
|
call = (int (*)(bool b)) dlsym(dl, "_nss_systemd_block");
|
||||||
_cleanup_close_ int fd = -1;
|
if (!call)
|
||||||
union sockaddr_union sa;
|
/* If the file is is installed but lacks the symbol we expect, things are weird, let's complain */
|
||||||
socklen_t salen;
|
return log_debug_errno(SYNTHETIC_ERRNO(ELIBBAD),
|
||||||
int r;
|
"Unable to find symbol _nss_systemd_block in libnss_systemd.so.2: %s", dlerror());
|
||||||
|
|
||||||
/* Tests whether the NSS compatibility logic is currently turned on for the invoking thread. Returns
|
return call(b);
|
||||||
* true if NSS compatibility is turned on, i.e. whether NSS records shall be synthesized from complex
|
|
||||||
* user records. */
|
|
||||||
|
|
||||||
r = userdb_thread_sockaddr(&sa.un, &salen);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
|
|
||||||
if (fd < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
/* Try to connect(). This doesn't do anything really, except that it checks whether the socket
|
|
||||||
* address is bound at all. */
|
|
||||||
if (connect(fd, &sa.sa, salen) < 0) {
|
|
||||||
if (errno == ECONNREFUSED) /* the socket is not bound, hence NSS emulation shall be done */
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int userdb_nss_compat_disable(void) {
|
|
||||||
_cleanup_close_ int fd = -1;
|
|
||||||
union sockaddr_union sa;
|
|
||||||
socklen_t salen;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
/* Turn off the NSS compatibility logic for the invoking thread. By default NSS records are
|
|
||||||
* synthesized for all complex user records looked up via NSS. If this call is invoked this is
|
|
||||||
* disabled for the invoking thread, but only for it. A caller that natively supports the varlink
|
|
||||||
* user record protocol may use that to turn off the compatibility for NSS lookups. */
|
|
||||||
|
|
||||||
r = userdb_thread_sockaddr(&sa.un, &salen);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
|
||||||
if (fd < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
if (bind(fd, &sa.sa, salen) < 0) {
|
|
||||||
if (errno == EADDRINUSE) /* lock already taken, convert this into a recognizable error */
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TAKE_FD(fd);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,5 +38,4 @@ int membershipdb_all(UserDBFlags flags, UserDBIterator **ret);
|
||||||
int membershipdb_iterator_get(UserDBIterator *iterator, char **user, char **group);
|
int membershipdb_iterator_get(UserDBIterator *iterator, char **user, char **group);
|
||||||
int membershipdb_by_group_strv(const char *name, UserDBFlags flags, char ***ret);
|
int membershipdb_by_group_strv(const char *name, UserDBFlags flags, char ***ret);
|
||||||
|
|
||||||
int userdb_nss_compat_is_enabled(void);
|
int userdb_block_nss_systemd(int b);
|
||||||
int userdb_nss_compat_disable(void);
|
|
||||||
|
|
|
@ -1898,7 +1898,7 @@ static int run(int argc, char *argv[]) {
|
||||||
|
|
||||||
r = mac_selinux_init();
|
r = mac_selinux_init();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "SELinux setup failed: %m");
|
return r;
|
||||||
|
|
||||||
/* If command line arguments are specified along with --replace, read all
|
/* If command line arguments are specified along with --replace, read all
|
||||||
* configuration files and insert the positional arguments at the specified
|
* configuration files and insert the positional arguments at the specified
|
||||||
|
|
|
@ -377,7 +377,10 @@ static int context_write_data_local_rtc(Context *c) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mac_selinux_init();
|
r = mac_selinux_init();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
return write_string_file_atomic_label("/etc/adjtime", w);
|
return write_string_file_atomic_label("/etc/adjtime", w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3262,7 +3262,9 @@ static int run(int argc, char *argv[]) {
|
||||||
|
|
||||||
umask(0022);
|
umask(0022);
|
||||||
|
|
||||||
mac_selinux_init();
|
r = mac_selinux_init();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
items = ordered_hashmap_new(&item_array_hash_ops);
|
items = ordered_hashmap_new(&item_array_hash_ops);
|
||||||
globs = ordered_hashmap_new(&item_array_hash_ops);
|
globs = ordered_hashmap_new(&item_array_hash_ops);
|
||||||
|
|
|
@ -124,7 +124,10 @@ static int run(int argc, char *argv[]) {
|
||||||
|
|
||||||
log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level());
|
log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level());
|
||||||
|
|
||||||
mac_selinux_init();
|
r = mac_selinux_init();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
return udevadm_main(argc, argv);
|
return udevadm_main(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1863,7 +1863,7 @@ int run_udevd(int argc, char *argv[]) {
|
||||||
|
|
||||||
r = mac_selinux_init();
|
r = mac_selinux_init();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Could not initialize labelling: %m");
|
return r;
|
||||||
|
|
||||||
r = mkdir_errno_wrapper("/run/udev", 0755);
|
r = mkdir_errno_wrapper("/run/udev", 0755);
|
||||||
if (r < 0 && r != -EEXIST)
|
if (r < 0 && r != -EEXIST)
|
||||||
|
|
|
@ -49,10 +49,8 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
r = mac_selinux_init();
|
r = mac_selinux_init();
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
log_error_errno(r, "SELinux setup failed: %m");
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
|
||||||
|
|
||||||
r = apply_timestamp("/etc/.updated", &st.st_mtim);
|
r = apply_timestamp("/etc/.updated", &st.st_mtim);
|
||||||
q = apply_timestamp("/var/.updated", &st.st_mtim);
|
q = apply_timestamp("/var/.updated", &st.st_mtim);
|
||||||
|
|
|
@ -25,7 +25,9 @@ static int run(int argc, char *argv[]) {
|
||||||
|
|
||||||
umask(0022);
|
umask(0022);
|
||||||
|
|
||||||
mac_selinux_init();
|
r = mac_selinux_init();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
if (streq(argv[1], "start")) {
|
if (streq(argv[1], "start")) {
|
||||||
r = unlink_or_warn("/run/nologin");
|
r = unlink_or_warn("/run/nologin");
|
||||||
|
|
|
@ -660,7 +660,6 @@ static int process_connection(VarlinkServer *server, int fd) {
|
||||||
static int run(int argc, char *argv[]) {
|
static int run(int argc, char *argv[]) {
|
||||||
usec_t start_time, listen_idle_usec, last_busy_usec = USEC_INFINITY;
|
usec_t start_time, listen_idle_usec, last_busy_usec = USEC_INFINITY;
|
||||||
_cleanup_(varlink_server_unrefp) VarlinkServer *server = NULL;
|
_cleanup_(varlink_server_unrefp) VarlinkServer *server = NULL;
|
||||||
_cleanup_close_ int lock = -1;
|
|
||||||
unsigned n_iterations = 0;
|
unsigned n_iterations = 0;
|
||||||
int m, listen_fd, r;
|
int m, listen_fd, r;
|
||||||
|
|
||||||
|
@ -697,8 +696,8 @@ static int run(int argc, char *argv[]) {
|
||||||
return log_error_errno(r, "Failed to parse USERDB_FIXED_WORKER: %m");
|
return log_error_errno(r, "Failed to parse USERDB_FIXED_WORKER: %m");
|
||||||
listen_idle_usec = r ? USEC_INFINITY : LISTEN_IDLE_USEC;
|
listen_idle_usec = r ? USEC_INFINITY : LISTEN_IDLE_USEC;
|
||||||
|
|
||||||
lock = userdb_nss_compat_disable();
|
r = userdb_block_nss_systemd(true);
|
||||||
if (lock < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to disable userdb NSS compatibility: %m");
|
return log_error_errno(r, "Failed to disable userdb NSS compatibility: %m");
|
||||||
|
|
||||||
start_time = now(CLOCK_MONOTONIC);
|
start_time = now(CLOCK_MONOTONIC);
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
|
||||||
|
|
||||||
|
all setup run clean clean-again:
|
||||||
|
@basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
|
||||||
|
|
||||||
|
# finish option is used to run checks that can only be run outside of
|
||||||
|
# the test execution. Example case, honor first shutdown, proof is obtained
|
||||||
|
# from the console output as the image shuts down. This does not show up in
|
||||||
|
# the journal so the output from the do_test is captured in a file in /tmp.
|
||||||
|
# Without the use of finish the test will still pass because if it fails
|
||||||
|
# the test will loop and will be terminated via a command timeout.
|
||||||
|
# This just provides concrete confirmation.
|
||||||
|
finish:
|
||||||
|
@basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./fini.sh --$@
|
||||||
|
|
||||||
|
.PHONY: all setup run clean clean-again
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/bash
|
||||||
|
TEST_DESCRIPTION="test honor first shutdown"
|
||||||
|
|
||||||
|
if grep -q "Shutdown is already active. Skipping emergency action request" /tmp/honorfirstshutdown.log; then
|
||||||
|
echo "$TEST_DESCRIPTION [pass]"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "$TEST_DESCRIPTION [fail]"
|
||||||
|
exit 1
|
||||||
|
fi
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
. $TEST_BASE_DIR/test-functions
|
||||||
|
TEST_REQUIRE_INSTALL_TESTS=0
|
||||||
|
TEST_DESCRIPTION="testing honor first shutdown"
|
||||||
|
#INTERACTIVE_DEBUG=1
|
||||||
|
TEST_NO_QEMU=1
|
||||||
|
|
||||||
|
#Using timeout because if the test fails it can loop.
|
||||||
|
# The reason is because the poweroff executed by end.service
|
||||||
|
# could turn into a reboot if the test fails.
|
||||||
|
NSPAWN_TIMEOUT=20
|
||||||
|
|
||||||
|
#Remove this file if it exists. this is used along with
|
||||||
|
# the make target "finish". Since concrete confirmaion is
|
||||||
|
# only found from the console during the poweroff.
|
||||||
|
rm -f /tmp/honorfirstshutdown.log >/dev/null
|
||||||
|
|
||||||
|
do_test "$@" 52 > /tmp/honorfirstshutdown.log
|
|
@ -28,6 +28,8 @@ install_subdir('testsuite-28.units',
|
||||||
install_dir : testdata_dir)
|
install_dir : testdata_dir)
|
||||||
install_subdir('testsuite-30.units',
|
install_subdir('testsuite-30.units',
|
||||||
install_dir : testdata_dir)
|
install_dir : testdata_dir)
|
||||||
|
install_subdir('testsuite-52.units',
|
||||||
|
install_dir : testdata_dir)
|
||||||
|
|
||||||
testsuite08_dir = testdata_dir + '/testsuite-08.units'
|
testsuite08_dir = testdata_dir + '/testsuite-08.units'
|
||||||
install_data('testsuite-08.units/-.mount',
|
install_data('testsuite-08.units/-.mount',
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Testsuite service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/lib/systemd/tests/testdata/%N.units/%N.sh
|
||||||
|
Type=oneshot
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -ex
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
if ! test -x /usr/lib/systemd/tests/testdata/units/test-honor-first-shutdown.sh ; then
|
||||||
|
echo "honor-first-shutdown script not found - FAIL" > /testok
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
systemd-analyze log-level debug
|
||||||
|
systemd-analyze log-target console
|
||||||
|
|
||||||
|
systemctl enable test-honor-first-shutdown.service
|
||||||
|
systemctl start test-honor-first-shutdown.service
|
||||||
|
|
||||||
|
echo OK > /testok
|
||||||
|
|
||||||
|
exit 0
|
|
@ -0,0 +1,11 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Honor First Shutdown feature
|
||||||
|
After=multi-user.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
|
||||||
|
ExecStop=sh -c 'kill -SIGKILL $MAINPID'
|
||||||
|
FailureAction=reboot
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
echo "Honor first shutdown test script"
|
||||||
|
sleep infinity;
|
Loading…
Reference in New Issue