summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.github/workflows/build_test.sh26
-rw-r--r--.github/workflows/build_test.yml4
-rw-r--r--.github/workflows/cflite_pr.yml4
-rw-r--r--.github/workflows/cifuzz.yml4
-rw-r--r--.github/workflows/mkosi.yml8
-rwxr-xr-x.github/workflows/unit_tests.sh5
-rw-r--r--.github/workflows/unit_tests.yml2
-rw-r--r--TODO21
-rw-r--r--hwdb.d/60-input-id.hwdb4
-rw-r--r--man/loader.conf.xml46
-rw-r--r--mkosi.kernel.config3
-rwxr-xr-xmkosi.presets/system/mkosi.kernel.build2
-rw-r--r--src/boot/measure.c27
-rw-r--r--src/core/manager.c11
-rw-r--r--src/home/user-record-sign.c21
-rw-r--r--src/journal/journald-wall.c4
-rw-r--r--src/login/logind-dbus.c5
-rw-r--r--src/login/logind-wall.c (renamed from src/login/logind-utmp.c)4
-rw-r--r--src/login/meson.build2
-rw-r--r--src/shared/meson.build1
-rw-r--r--src/shared/openssl-util.c43
-rw-r--r--src/shared/openssl-util.h2
-rw-r--r--src/shared/utmp-wtmp.c127
-rw-r--r--src/shared/utmp-wtmp.h15
-rw-r--r--src/shared/wall.c203
-rw-r--r--src/shared/wall.h11
-rw-r--r--src/tty-ask-password-agent/tty-ask-password-agent.c8
-rw-r--r--test/README.testsuite2
28 files changed, 363 insertions, 252 deletions
diff --git a/.github/workflows/build_test.sh b/.github/workflows/build_test.sh
index a512e5101d..c0872117ab 100755
--- a/.github/workflows/build_test.sh
+++ b/.github/workflows/build_test.sh
@@ -68,8 +68,6 @@ LINKER="${LINKER:?}"
CRYPTOLIB="${CRYPTOLIB:?}"
RELEASE="$(lsb_release -cs)"
-bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse' >>/etc/apt/sources.list"
-
# Note: As we use postfixed clang/gcc binaries, we need to override $AR
# as well, otherwise meson falls back to ar from binutils which
# doesn't work with LTO
@@ -79,12 +77,13 @@ if [[ "$COMPILER" == clang ]]; then
AR="llvm-ar-$COMPILER_VERSION"
# Prefer the distro version if available
- if ! apt install --dry-run "llvm-$COMPILER_VERSION" >/dev/null; then
+ if ! apt-get -y install --dry-run "llvm-$COMPILER_VERSION" >/dev/null; then
# Latest LLVM stack deb packages provided by https://apt.llvm.org/
# Following snippet was partly borrowed from https://apt.llvm.org/llvm.sh
- wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | gpg --yes --dearmor --output /usr/share/keyrings/apt-llvm-org.gpg
- printf "deb [signed-by=/usr/share/keyrings/apt-llvm-org.gpg] http://apt.llvm.org/%s/ llvm-toolchain-%s-%s main\n" \
- "$RELEASE" "$RELEASE" "$COMPILER_VERSION" >/etc/apt/sources.list.d/llvm-toolchain.list
+ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | \
+ sudo gpg --yes --dearmor --output /usr/share/keyrings/apt-llvm-org.gpg
+ echo "deb [signed-by=/usr/share/keyrings/apt-llvm-org.gpg] http://apt.llvm.org/$RELEASE/ llvm-toolchain-$RELEASE-$COMPILER_VERSION main" | \
+ sudo tee /etc/apt/sources.list.d/llvm-toolchain.list
fi
PACKAGES+=("clang-$COMPILER_VERSION" "lldb-$COMPILER_VERSION" "python3-lldb-$COMPILER_VERSION" "lld-$COMPILER_VERSION" "clangd-$COMPILER_VERSION")
@@ -93,10 +92,10 @@ elif [[ "$COMPILER" == gcc ]]; then
CXX="g++-$COMPILER_VERSION"
AR="gcc-ar-$COMPILER_VERSION"
- if ! apt install --dry-run "gcc-$COMPILER_VERSION" >/dev/null; then
+ if ! apt-get -y install --dry-run "gcc-$COMPILER_VERSION" >/dev/null; then
# Latest gcc stack deb packages provided by
# https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test
- add-apt-repository -y ppa:ubuntu-toolchain-r/test
+ sudo add-apt-repository -y --no-update ppa:ubuntu-toolchain-r/test
fi
PACKAGES+=("gcc-$COMPILER_VERSION" "gcc-$COMPILER_VERSION-multilib")
@@ -105,10 +104,11 @@ else
fi
# PPA with some newer build dependencies (like zstd)
-add-apt-repository -y ppa:upstream-systemd-ci/systemd-ci
-apt-get -y update
-apt-get -y build-dep systemd
-apt-get -y install "${PACKAGES[@]}"
+sudo add-apt-repository -y --no-update ppa:upstream-systemd-ci/systemd-ci
+sudo add-apt-repository -y --no-update --enable-source
+sudo apt-get -y update
+sudo apt-get -y build-dep systemd
+sudo apt-get -y install "${PACKAGES[@]}"
# Install more or less recent meson and ninja with pip, since the distro versions don't
# always support all the features we need (like --optimization=). Since the build-dep
# command above installs the distro versions, let's install the pip ones just
@@ -139,7 +139,7 @@ for args in "${ARGS[@]}"; do
CXX="$CXX" CXX_LD="$LD" CXXFLAGS="-Werror" \
meson setup \
-Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true --werror \
- -Dnobody-group=nogroup -Dcryptolib="${CRYPTOLIB:?}" \
+ -Dnobody-group=nogroup -Dcryptolib="${CRYPTOLIB:?}" -Ddebug=false \
$args build; then
cat build/meson-logs/meson-log.txt
diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml
index 16dcd30c08..ccbbe26ecd 100644
--- a/.github/workflows/build_test.yml
+++ b/.github/workflows/build_test.yml
@@ -34,5 +34,5 @@ jobs:
steps:
- name: Repository checkout
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
- - name: ${{ format('Build check ({0}-{1}-{2}-{3})', env.COMPILER, env.COMPILER_VERSION, env.LINKER, env.CRYPTOLIB) }}
- run: sudo -E .github/workflows/build_test.sh
+ - name: Build check
+ run: .github/workflows/build_test.sh
diff --git a/.github/workflows/cflite_pr.yml b/.github/workflows/cflite_pr.yml
index a35a97f046..707ea0b6ba 100644
--- a/.github/workflows/cflite_pr.yml
+++ b/.github/workflows/cflite_pr.yml
@@ -23,13 +23,13 @@ jobs:
matrix:
sanitizer: [address, undefined, memory]
steps:
- - name: Build Fuzzers (${{ matrix.sanitizer }})
+ - name: Build Fuzzers
id: build
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
with:
sanitizer: ${{ matrix.sanitizer }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- - name: Run Fuzzers (${{ matrix.sanitizer }})
+ - name: Run Fuzzers
id: run
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
with:
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml
index a7e4d2b842..f7530b7507 100644
--- a/.github/workflows/cifuzz.yml
+++ b/.github/workflows/cifuzz.yml
@@ -39,7 +39,7 @@ jobs:
security-events: write
steps:
- - name: Build Fuzzers (${{ matrix.sanitizer }})
+ - name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
@@ -51,7 +51,7 @@ jobs:
sanitizer: ${{ matrix.sanitizer }}
architecture: ${{ matrix.architecture }}
output-sarif: true
- - name: Run Fuzzers (${{ matrix.sanitizer }})
+ - name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'systemd'
diff --git a/.github/workflows/mkosi.yml b/.github/workflows/mkosi.yml
index c353423c58..5b70c607c2 100644
--- a/.github/workflows/mkosi.yml
+++ b/.github/workflows/mkosi.yml
@@ -140,14 +140,14 @@ jobs:
- name: Generate secure boot key
run: mkosi --debug genkey
- - name: Show ${{ matrix.distro }} image summary
+ - name: Show image summary
run: mkosi summary
- - name: Build ${{ matrix.distro }}
+ - name: Build
run: mkosi --debug
- - name: Boot ${{ matrix.distro }} systemd-nspawn
+ - name: Boot systemd-nspawn
run: test "$(sudo mkosi --debug boot 1>&2; echo $?)" -eq 123
- - name: Boot ${{ matrix.distro }} QEMU
+ - name: Boot QEMU
run: timeout -k 30 10m test "$(mkosi --debug qemu 1>&2; echo $?)" -eq 123
diff --git a/.github/workflows/unit_tests.sh b/.github/workflows/unit_tests.sh
index 0985817b72..a5b98e089b 100755
--- a/.github/workflows/unit_tests.sh
+++ b/.github/workflows/unit_tests.sh
@@ -3,7 +3,6 @@
# shellcheck disable=SC2206
PHASES=(${@:-SETUP RUN RUN_ASAN_UBSAN CLEANUP})
-RELEASE="$(lsb_release -cs)"
ADDITIONAL_DEPS=(
clang
expect
@@ -46,9 +45,9 @@ for phase in "${PHASES[@]}"; do
case $phase in
SETUP)
info "Setup phase"
- bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse' >>/etc/apt/sources.list"
# PPA with some newer build dependencies
- add-apt-repository -y ppa:upstream-systemd-ci/systemd-ci
+ add-apt-repository -y --no-update ppa:upstream-systemd-ci/systemd-ci
+ add-apt-repository -y --no-update --enable-source
apt-get -y update
apt-get -y build-dep systemd
apt-get -y install "${ADDITIONAL_DEPS[@]}"
diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml
index 051e8ec3bf..e2dd8c3da2 100644
--- a/.github/workflows/unit_tests.yml
+++ b/.github/workflows/unit_tests.yml
@@ -39,7 +39,7 @@ jobs:
# Pass only specific env variables through sudo, to avoid having
# the already existing XDG_* stuff on the "other side"
sudo --preserve-env=CRYPTOLIB,GITHUB_ACTIONS,CI .github/workflows/unit_tests.sh SETUP
- - name: Build & test (${{ matrix.run_phase }}-${{ matrix.cryptolib }})
+ - name: Build & test
run: sudo --preserve-env=CRYPTOLIB,GITHUB_ACTIONS,CI .github/workflows/unit_tests.sh RUN_${{ matrix.run_phase }}
env:
CRYPTOLIB: ${{ matrix.cryptolib }}
diff --git a/TODO b/TODO
index 4a258e5014..7e8d2a93e4 100644
--- a/TODO
+++ b/TODO
@@ -95,14 +95,6 @@ Janitorial Clean-ups:
Deprecations and removals:
-* homed: add a basic form of of secrets management to homed, that stores
- secrets in $HOME somewhere, is protected by the accounts own authentication
- mechanisms. Should implement something PKCS#11-like that can be used to
- implement emulated FIDO2 in unpriv userspace on top (which should happen
- outside of homed), emulated PKCS11, and libsecrets support. Operate with a
- 2nd key derived from volume key of the user, with which to wrap all
- keys. maintain keys in kernel keyring if possible.
-
* Remove any support for booting without /usr pre-mounted in the initrd entirely.
Update INITRD_INTERFACE.md accordingly.
@@ -144,6 +136,19 @@ Deprecations and removals:
Features:
+* ddi must be listed as block device fstype
+
+* measure some string via pcrphase whenever we end up booting into emergency
+ mode.
+
+* homed: add a basic form of of secrets management to homed, that stores
+ secrets in $HOME somewhere, is protected by the accounts own authentication
+ mechanisms. Should implement something PKCS#11-like that can be used to
+ implement emulated FIDO2 in unpriv userspace on top (which should happen
+ outside of homed), emulated PKCS11, and libsecrets support. Operate with a
+ 2nd key derived from volume key of the user, with which to wrap all
+ keys. maintain keys in kernel keyring if possible.
+
* add ConditionSecurity=stub-measured or so that checks if we are booted with
systemd-stub and its measurements
diff --git a/hwdb.d/60-input-id.hwdb b/hwdb.d/60-input-id.hwdb
index 802ed9a1e7..1c84777fe0 100644
--- a/hwdb.d/60-input-id.hwdb
+++ b/hwdb.d/60-input-id.hwdb
@@ -75,3 +75,7 @@ id-input:modalias:input:b0003v046Dp4066e0111*
id-input:modalias:input:b0003v068Ep00F2e0100*
ID_INPUT_ACCELEROMETER=0
ID_INPUT_JOYSTICK=1
+
+# TEX Shinobi Trackpoint
+id-input:modalias:input:b0003v04D9p0407e0111-e0,1,2,4*
+ ID_INPUT_POINTINGSTICK=1
diff --git a/man/loader.conf.xml b/man/loader.conf.xml
index 1c71a9b7de..0e9f6e6924 100644
--- a/man/loader.conf.xml
+++ b/man/loader.conf.xml
@@ -308,33 +308,43 @@
<programlisting>uuid=$(systemd-id128 new --uuid)
for key in PK KEK db; do
- openssl req -new -x509 -subj "/CN=${key}/" -keyout "${key}.key" -out "${key}.crt"
- openssl x509 -outform DER -in "${key}.crt" -out "${key}.der"
+ openssl req -new -x509 -subj "/CN=${key}/" -keyout "${key}.key" -out "${key}.pem"
+ openssl x509 -outform DER -in "${key}.pem" -out "${key}.der"
sbsiglist --owner "${uuid}" --type x509 --output "${key}.esl" "${key}.der"
done
-for key in MicWinProPCA2011_2011-10-19.crt MicCorUEFCA2011_2011-06-27.crt MicCorKEKCA2011_2011-06-24.crt; do
- curl "https://www.microsoft.com/pkiops/certs/${key}" --output "${key}"
- sbsiglist --owner 77fa9abd-0359-4d32-bd60-28f4e78f784b --type x509 --output "${key%crt}esl" "${key}"
+# See also: <ulink url="https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-secure-boot-key-creation-and-management-guidance">Windows Secure Boot Key Creation and Management Guidance</ulink>
+curl --location \
+ "https://go.microsoft.com/fwlink/p/?linkid=321192" -o ms-db-2011.der \
+ "https://go.microsoft.com/fwlink/p/?linkid=321185" -o ms-kek-2011.der \
+ "https://go.microsoft.com/fwlink/p/?linkid=321194" -o ms-uefi-db-2011.der \
+ "https://go.microsoft.com/fwlink/p/?linkid=2239775" -o ms-kek-2023.base64 \
+ "https://go.microsoft.com/fwlink/p/?linkid=2239776" -o ms-db-2023.base64 \
+ "https://go.microsoft.com/fwlink/p/?linkid=2239872" -o ms-uefi-db-2023.base64
+for key in ms-*.base64; do
+ base64 -d "${key}" >"${key%base64}der"
+done
+for key in ms-*.der; do
+ sbsiglist --owner 77fa9abd-0359-4d32-bd60-28f4e78f784b --type x509 --output "${key%der}esl" "${key}"
done
-# Optionally add Microsoft Windows Production CA 2011 (needed to boot into Windows).
-cat MicWinProPCA2011_2011-10-19.esl >>db.esl
+# Optionally add Microsoft Windows certificates (needed to boot into Windows).
+cat ms-db-*.esl >>db.esl
-# Optionally add Microsoft Corporation UEFI CA 2011 for firmware drivers / option ROMs
-# and third-party boot loaders (including shim). This is highly recommended on real
-# hardware as not including this may soft-brick your device (see next paragraph).
-cat MicCorUEFCA2011_2011-06-27.esl >>db.esl
+# Optionally add Microsoft UEFI certificates for firmware drivers / option ROMs and third-party
+# boot loaders (including shim). This is highly recommended on real hardware as not including this
+# may soft-brick your device (see next paragraph).
+cat ms-uefi-*.esl >>db.esl
-# Optionally add Microsoft Corporation KEK CA 2011. Recommended if either of the
-# Microsoft keys is used as the official UEFI revocation database is signed with this
-# key. The revocation database can be updated with <citerefentry project='man-pages'><refentrytitle>fwupdmgr</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
-cat MicCorKEKCA2011_2011-06-24.esl >>KEK.esl
+# Optionally add Microsoft KEK certificates. Recommended if either of the Microsoft keys is used as
+# the official UEFI revocation database is signed with this key. The revocation database can be
+# updated with <citerefentry project='man-pages'><refentrytitle>fwupdmgr</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
+cat ms-kek-*.esl >>KEK.esl
attr=NON_VOLATILE,RUNTIME_ACCESS,BOOTSERVICE_ACCESS,TIME_BASED_AUTHENTICATED_WRITE_ACCESS
-sbvarsign --attr ${attr} --key PK.key --cert PK.crt --output PK.auth PK PK.esl
-sbvarsign --attr ${attr} --key PK.key --cert PK.crt --output KEK.auth KEK KEK.esl
-sbvarsign --attr ${attr} --key KEK.key --cert KEK.crt --output db.auth db db.esl
+sbvarsign --attr "${attr}" --key PK.key --cert PK.pem --output PK.auth PK PK.esl
+sbvarsign --attr "${attr}" --key PK.key --cert PK.pem --output KEK.auth KEK KEK.esl
+sbvarsign --attr "${attr}" --key KEK.key --cert KEK.pem --output db.auth db db.esl
</programlisting>
<para>This feature is considered dangerous because even if all the required files are signed with the
diff --git a/mkosi.kernel.config b/mkosi.kernel.config
index 098d1c230f..77657c2240 100644
--- a/mkosi.kernel.config
+++ b/mkosi.kernel.config
@@ -132,6 +132,8 @@ CONFIG_NETFILTER=y
CONFIG_NETLABEL=y
CONFIG_NF_CONNTRACK_FTP=y
CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_CT_NETLINK=y
@@ -212,7 +214,6 @@ CONFIG_XFS_POSIX_ACL=y
# CONFIG_AGP is not set
# CONFIG_FB is not set
# CONFIG_HID is not set
-# CONFIG_USB is not set
# CONFIG_NETDEVSIM is not set
# CONFIG_NET_VENDOR_3COM is not set
diff --git a/mkosi.presets/system/mkosi.kernel.build b/mkosi.presets/system/mkosi.kernel.build
index 64cc48863f..5938330d4b 100755
--- a/mkosi.presets/system/mkosi.kernel.build
+++ b/mkosi.presets/system/mkosi.kernel.build
@@ -30,7 +30,7 @@ if [ -d "$SRCDIR"/mkosi.kernel/ ]; then
make O="$BUILDDIR" VERSION=99 INSTALL_MOD_PATH="$DESTDIR/usr" modules_install
make O="$BUILDDIR" VERSION=99 INSTALL_PATH="$DESTDIR/usr/lib/modules/$KERNEL_RELEASE" install
mkdir -p "$DESTDIR/usr/lib/kernel/selftests"
- make -C tools/testing/selftests -j "$(nproc)" O="$BUILDDIR" VERSION=99 KSFT_INSTALL_PATH="$DESTDIR/usr/lib/kernel/selftests" SKIP_TARGETS="" install
+ make -C tools/testing/selftests -j "$(nproc)" O="$BUILDDIR" VERSION=99 KSFT_INSTALL_PATH="$DESTDIR/usr/lib/kernel/selftests" SKIP_TARGETS="hid" install
mkdir -p "$DESTDIR"/usr/bin
ln -sf /usr/lib/kernel/selftests/bpf/bpftool "$DESTDIR/usr/bin/bpftool"
diff --git a/src/boot/measure.c b/src/boot/measure.c
index a62caf8a3f..45febe121a 100644
--- a/src/boot/measure.c
+++ b/src/boot/measure.c
@@ -837,31 +837,12 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
- _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* mdctx = NULL;
- mdctx = EVP_MD_CTX_new();
- if (!mdctx)
- return log_oom();
-
- if (EVP_DigestSignInit(mdctx, NULL, p->md, NULL, privkey) != 1)
- return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
- "Failed to initialize signature context.");
-
- if (EVP_DigestSignUpdate(mdctx, pcr_policy_digest.buffer, pcr_policy_digest.size) != 1)
- return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
- "Failed to sign data.");
-
+ _cleanup_free_ void *sig = NULL;
size_t ss;
- if (EVP_DigestSignFinal(mdctx, NULL, &ss) != 1)
- return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
- "Failed to finalize signature");
- _cleanup_free_ void *sig = malloc(ss);
- if (!sig)
- return log_oom();
-
- if (EVP_DigestSignFinal(mdctx, sig, &ss) != 1)
- return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
- "Failed to acquire signature data");
+ r = digest_and_sign(p->md, privkey, pcr_policy_digest.buffer, pcr_policy_digest.size, &sig, &ss);
+ if (r < 0)
+ return log_error_errno(r, "Failed to sign PCR policy: %m");
_cleanup_free_ void *pubkey_fp = NULL;
size_t pubkey_fp_size = 0;
diff --git a/src/core/manager.c b/src/core/manager.c
index 304abf4697..7492a0b1b8 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -4019,13 +4019,20 @@ static int manager_run_generators(Manager *m) {
_exit(r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
if (r < 0) {
- if (!ERRNO_IS_PRIVILEGE(r)) {
+ if (!ERRNO_IS_PRIVILEGE(r) && r != -EINVAL) {
log_error_errno(r, "Failed to fork off sandboxing environment for executing generators: %m");
goto finish;
}
/* Failed to fork with new mount namespace? Maybe, running in a container environment with
- * seccomp or without capability. */
+ * seccomp or without capability.
+ *
+ * We also allow -EINVAL to allow running without CLONE_NEWNS.
+ *
+ * Also, when running on non-native userland architecture via systemd-nspawn and
+ * qemu-user-static QEMU-emulator, clone() with CLONE_NEWNS fails with EINVAL, see
+ * https://github.com/systemd/systemd/issues/28901.
+ */
log_debug_errno(r,
"Failed to fork off sandboxing environment for executing generators. "
"Falling back to execute generators without sandboxing: %m");
diff --git a/src/home/user-record-sign.c b/src/home/user-record-sign.c
index cf72eaa556..dd099a0a6f 100644
--- a/src/home/user-record-sign.c
+++ b/src/home/user-record-sign.c
@@ -33,7 +33,6 @@ int user_record_sign(UserRecord *ur, EVP_PKEY *private_key, UserRecord **ret) {
_cleanup_(memstream_done) MemStream m = {};
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_(user_record_unrefp) UserRecord *signed_ur = NULL;
- _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *md_ctx = NULL;
_cleanup_free_ char *text = NULL, *key = NULL;
_cleanup_free_ void *signature = NULL;
size_t signature_size = 0;
@@ -48,23 +47,9 @@ int user_record_sign(UserRecord *ur, EVP_PKEY *private_key, UserRecord **ret) {
if (r < 0)
return r;
- md_ctx = EVP_MD_CTX_new();
- if (!md_ctx)
- return -ENOMEM;
-
- if (EVP_DigestSignInit(md_ctx, NULL, NULL, NULL, private_key) <= 0)
- return -EIO;
-
- /* Request signature size */
- if (EVP_DigestSign(md_ctx, NULL, &signature_size, (uint8_t*) text, strlen(text)) <= 0)
- return -EIO;
-
- signature = malloc(signature_size);
- if (!signature)
- return -ENOMEM;
-
- if (EVP_DigestSign(md_ctx, signature, &signature_size, (uint8_t*) text, strlen(text)) <= 0)
- return -EIO;
+ r = digest_and_sign(/* md= */ NULL, private_key, text, SIZE_MAX, &signature, &signature_size);
+ if (r < 0)
+ return r;
f = memstream_init(&m);
if (!f)
diff --git a/src/journal/journald-wall.c b/src/journal/journald-wall.c
index 21ec5a785b..c8d92c4d3e 100644
--- a/src/journal/journald-wall.c
+++ b/src/journal/journald-wall.c
@@ -6,7 +6,7 @@
#include "journald-wall.h"
#include "process-util.h"
#include "string-util.h"
-#include "utmp-wtmp.h"
+#include "wall.h"
void server_forward_wall(
Server *s,
@@ -48,7 +48,7 @@ void server_forward_wall(
} else
l = message;
- r = utmp_wall(l, "systemd-journald", NULL, NULL, NULL);
+ r = wall(l, "systemd-journald", NULL, NULL, NULL);
if (r < 0)
log_debug_errno(r, "Failed to send wall message: %m");
}
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 2d1af602c0..dcbd195fe2 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -57,6 +57,7 @@
#include "user-util.h"
#include "utmp-wtmp.h"
#include "virt.h"
+#include "wall.h"
/* As a random fun fact sysvinit had a 252 (256-(strlen(" \r\n")+1))
* character limit for the wall message.
@@ -2342,8 +2343,8 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
"MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_CANCELED_STR,
username ? "OPERATOR=%s" : NULL, username);
- utmp_wall("System shutdown has been cancelled",
- username, tty, logind_wall_tty_filter, m);
+ (void) wall("System shutdown has been cancelled",
+ username, tty, logind_wall_tty_filter, m);
}
reset_scheduled_shutdown(m);
diff --git a/src/login/logind-utmp.c b/src/login/logind-wall.c
index 4db127a4c5..aa73522334 100644
--- a/src/login/logind-utmp.c
+++ b/src/login/logind-wall.c
@@ -18,7 +18,7 @@
#include "strv.h"
#include "unit-name.h"
#include "user-util.h"
-#include "utmp-wtmp.h"
+#include "wall.h"
static usec_t when_wall(usec_t n, usec_t elapse) {
static const int wall_timers[] = {
@@ -94,7 +94,7 @@ static int warn_wall(Manager *m, usec_t n) {
username ? "OPERATOR=%s" : NULL, username);
if (m->enable_wall_messages)
- utmp_wall(l, username, m->scheduled_shutdown_tty, logind_wall_tty_filter, m);
+ (void) wall(l, username, m->scheduled_shutdown_tty, logind_wall_tty_filter, m);
return 1;
}
diff --git a/src/login/meson.build b/src/login/meson.build
index 9804a36ce1..276e920dfc 100644
--- a/src/login/meson.build
+++ b/src/login/meson.build
@@ -26,7 +26,7 @@ liblogind_core_sources = files(
'logind-session.c',
'logind-user-dbus.c',
'logind-user.c',
- 'logind-utmp.c',
+ 'logind-wall.c',
)
liblogind_core_sources += [logind_gperf_c]
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 01e85b617f..67f4f4517d 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -168,6 +168,7 @@ shared_sources = files(
'verbs.c',
'vlan-util.c',
'volatile-util.c',
+ 'wall.c',
'watchdog.c',
'web-util.c',
'wifi-util.c',
diff --git a/src/shared/openssl-util.c b/src/shared/openssl-util.c
index 3d3d8090f8..31a1a55df7 100644
--- a/src/shared/openssl-util.c
+++ b/src/shared/openssl-util.c
@@ -545,6 +545,49 @@ int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_s
return 0;
}
+int digest_and_sign(
+ const EVP_MD *md,
+ EVP_PKEY *privkey,
+ const void *data, size_t size,
+ void **ret, size_t *ret_size) {
+
+ assert(privkey);
+ assert(ret);
+ assert(ret_size);
+
+ if (size == 0)
+ data = ""; /* make sure to pass a valid pointer to OpenSSL */
+ else {
+ assert(data);
+
+ if (size == SIZE_MAX) /* If SIZE_MAX input is a string whose size we determine automatically */
+ size = strlen(data);
+ }
+
+ _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
+ if (!mdctx)
+ return log_openssl_errors("Failed to create new EVP_MD_CTX");
+
+ if (EVP_DigestSignInit(mdctx, NULL, md, NULL, privkey) != 1)
+ return log_openssl_errors("Failed to initialize signature context");
+
+ /* Determine signature size */
+ size_t ss;
+ if (EVP_DigestSign(mdctx, NULL, &ss, data, size) != 1)
+ return log_openssl_errors("Failed to determine size of signature");
+
+ _cleanup_free_ void *sig = malloc(ss);
+ if (!sig)
+ return log_oom_debug();
+
+ if (EVP_DigestSign(mdctx, sig, &ss, data, size) != 1)
+ return log_openssl_errors("Failed to sign data");
+
+ *ret = TAKE_PTR(sig);
+ *ret_size = ss;
+ return 0;
+}
+
# if PREFER_OPENSSL
int string_hashsum(
const char *s,
diff --git a/src/shared/openssl-util.h b/src/shared/openssl-util.h
index 90158f589b..4ea82b5f27 100644
--- a/src/shared/openssl-util.h
+++ b/src/shared/openssl-util.h
@@ -75,6 +75,8 @@ int ecc_pkey_new(int curve_id, EVP_PKEY **ret);
int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_size);
+int digest_and_sign(const EVP_MD *md, EVP_PKEY *privkey, const void *data, size_t size, void **ret, size_t *ret_size);
+
#else
typedef struct X509 X509;
diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c
index c79764ced0..c90e07d4d1 100644
--- a/src/shared/utmp-wtmp.c
+++ b/src/shared/utmp-wtmp.c
@@ -280,130 +280,3 @@ int utmp_put_runlevel(int runlevel, int previous) {
return write_entry_both(&store);
}
-
-#define TIMEOUT_USEC (50 * USEC_PER_MSEC)
-
-static int write_to_terminal(const char *tty, const char *message) {
- _cleanup_close_ int fd = -EBADF;
- const char *p;
- size_t left;
- usec_t end;
-
- assert(tty);
- assert(message);
-
- fd = open(tty, O_WRONLY|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return -errno;
- if (!isatty(fd))
- return -ENOTTY;
-
- p = message;
- left = strlen(message);
-
- end = usec_add(now(CLOCK_MONOTONIC), TIMEOUT_USEC);
-
- while (left > 0) {
- ssize_t n;
- usec_t t;
- int k;
-
- t = now(CLOCK_MONOTONIC);
- if (t >= end)
- return -ETIME;
-
- k = fd_wait_for_event(fd, POLLOUT, end - t);
- if (ERRNO_IS_NEG_TRANSIENT(k))
- continue;
- if (k < 0)
- return k;
- if (k == 0)
- return -ETIME;
-
- n = write(fd, p, left);
- if (n < 0) {
- if (ERRNO_IS_TRANSIENT(errno))
- continue;
-
- return -errno;
- }
-
- assert((size_t) n <= left);
-
- p += n;
- left -= n;
- }
-
- return 0;
-}
-
-int utmp_wall(
- const char *message,
- const char *username,
- const char *origin_tty,
- bool (*match_tty)(const char *tty, bool is_local, void *userdata),
- void *userdata) {
-
- _unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
- _cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *stdin_tty = NULL;
- struct utmpx *u;
- int r;
-
- hn = gethostname_malloc();
- if (!hn)
- return -ENOMEM;
- if (!username) {
- un = getlogname_malloc();
- if (!un)
- return -ENOMEM;
- }
-
- if (!origin_tty) {
- getttyname_harder(STDIN_FILENO, &stdin_tty);
- origin_tty = stdin_tty;
- }
-
- if (asprintf(&text,
- "\r\n"
- "Broadcast message from %s@%s%s%s (%s):\r\n\r\n"
- "%s\r\n\r\n",
- un ?: username, hn,
- origin_tty ? " on " : "", strempty(origin_tty),
- FORMAT_TIMESTAMP(now(CLOCK_REALTIME)),
- message) < 0)
- return -ENOMEM;
-
- utmpx = utxent_start();
-
- r = 0;
-
- while ((u = getutxent())) {
- _cleanup_free_ char *buf = NULL;
- const char *path;
- int q;
-
- if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
- continue;
-
- /* This access is fine, because strlen("/dev/") < 32 (UT_LINESIZE) */
- if (path_startswith(u->ut_line, "/dev/"))
- path = u->ut_line;
- else {
- if (asprintf(&buf, "/dev/%.*s", (int) sizeof(u->ut_line), u->ut_line) < 0)
- return -ENOMEM;
- path = buf;
- }
-
- /* It seems that the address field is always set for remote logins.
- * For local logins and other local entries, we get [0,0,0,0]. */
- bool is_local = memeqzero(u->ut_addr_v6, sizeof(u->ut_addr_v6));
-
- if (!match_tty || match_tty(path, is_local, userdata)) {
- q = write_to_terminal(path, text);
- if (q < 0)
- r = q;
- }
- }
-
- return r;
-}
diff --git a/src/shared/utmp-wtmp.h b/src/shared/utmp-wtmp.h
index 97be719abf..ec1e27771e 100644
--- a/src/shared/utmp-wtmp.h
+++ b/src/shared/utmp-wtmp.h
@@ -18,13 +18,6 @@ int utmp_put_runlevel(int runlevel, int previous);
int utmp_put_dead_process(const char *id, pid_t pid, int code, int status);
int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line, int ut_type, const char *user);
-int utmp_wall(
- const char *message,
- const char *username,
- const char *origin_tty,
- bool (*match_tty)(const char *tty, bool is_local, void *userdata),
- void *userdata);
-
static inline bool utxent_start(void) {
setutxent();
return true;
@@ -54,13 +47,5 @@ static inline int utmp_put_dead_process(const char *id, pid_t pid, int code, int
static inline int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line, int ut_type, const char *user) {
return 0;
}
-static inline int utmp_wall(
- const char *message,
- const char *username,
- const char *origin_tty,
- bool (*match_tty)(const char *tty, bool is_local, void *userdata),
- void *userdata) {
- return 0;
-}
#endif /* ENABLE_UTMP */
diff --git a/src/shared/wall.c b/src/shared/wall.c
new file mode 100644
index 0000000000..e99fd9029c
--- /dev/null
+++ b/src/shared/wall.c
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <errno.h>
+#include <poll.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sd-login.h"
+
+#include "errno-util.h"
+#include "fd-util.h"
+#include "hostname-util.h"
+#include "io-util.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "terminal-util.h"
+#include "user-util.h"
+#include "utmp-wtmp.h"
+#include "wall.h"
+
+#define TIMEOUT_USEC (50 * USEC_PER_MSEC)
+
+static int write_to_terminal(const char *tty, const char *message) {
+ _cleanup_close_ int fd = -EBADF;
+ const char *p;
+ size_t left;
+ usec_t end;
+
+ assert(tty);
+ assert(message);
+
+ fd = open(tty, O_WRONLY|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+ if (!isatty(fd))
+ return -ENOTTY;
+
+ p = message;
+ left = strlen(message);
+
+ end = usec_add(now(CLOCK_MONOTONIC), TIMEOUT_USEC);
+
+ while (left > 0) {
+ ssize_t n;
+ usec_t t;
+ int k;
+
+ t = now(CLOCK_MONOTONIC);
+ if (t >= end)
+ return -ETIME;
+
+ k = fd_wait_for_event(fd, POLLOUT, end - t);
+ if (ERRNO_IS_NEG_TRANSIENT(k))
+ continue;
+ if (k < 0)
+ return k;
+ if (k == 0)
+ return -ETIME;
+
+ n = write(fd, p, left);
+ if (n < 0) {
+ if (ERRNO_IS_TRANSIENT(errno))
+ continue;
+
+ return -errno;
+ }
+
+ assert((size_t) n <= left);
+
+ p += n;
+ left -= n;
+ }
+
+ return 0;
+}
+
+#if ENABLE_UTMP
+static int do_wall(
+ const char *message,
+ const char *username,
+ const char *origin_tty,
+ bool (*match_tty)(const char *tty, bool is_local, void *userdata),
+ void *userdata) {
+
+ _unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
+ struct utmpx *u;
+ int r;
+
+ utmpx = utxent_start();
+
+ r = 0;
+
+ while ((u = getutxent())) {
+ _cleanup_free_ char *buf = NULL;
+ const char *path;
+ int q;
+
+ if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
+ continue;
+
+ /* This access is fine, because strlen("/dev/") < 32 (UT_LINESIZE) */
+ if (path_startswith(u->ut_line, "/dev/"))
+ path = u->ut_line;
+ else {
+ if (asprintf(&buf, "/dev/%.*s", (int) sizeof(u->ut_line), u->ut_line) < 0)
+ return -ENOMEM;
+ path = buf;
+ }
+
+ /* It seems that the address field is always set for remote logins.
+ * For local logins and other local entries, we get [0,0,0,0]. */
+ bool is_local = memeqzero(u->ut_addr_v6, sizeof(u->ut_addr_v6));
+
+ if (!match_tty || match_tty(path, is_local, userdata)) {
+ q = write_to_terminal(path, message);
+ if (q < 0)
+ r = q;
+ }
+ }
+
+ return r;
+}
+
+#else
+
+static int do_wall(
+ const char *message,
+ const char *username,
+ const char *origin_tty,
+ bool (*match_tty)(const char *tty, bool is_local, void *userdata),
+ void *userdata) {
+
+ int r;
+ _cleanup_strv_free_ char **sessions = NULL;
+
+ r = sd_get_sessions(&sessions);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(s, sessions) {
+ _cleanup_free_ char *path = NULL, *tty = NULL, *rhost = NULL;
+ int q;
+
+ q = sd_session_get_tty(*s, &tty);
+ if (q < 0) {
+ if (q != -ENXIO && q != -ENODATA)
+ r = q;
+ continue;
+ }
+
+ path = strjoin("/dev/", tty);
+ if (!path)
+ return -ENOMEM;
+
+ (void) sd_session_get_remote_host(*s, &rhost);
+ bool is_local = !rhost;
+
+ if (!match_tty || match_tty(path, is_local, userdata)) {
+ q = write_to_terminal(path, message);
+ if (q < 0)
+ r = q;
+ }
+ }
+ return r;
+}
+
+#endif
+
+int wall(
+ const char *message,
+ const char *username,
+ const char *origin_tty,
+ bool (*match_tty)(const char *tty, bool is_local, void *userdata),
+ void *userdata) {
+
+ _cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *stdin_tty = NULL;
+
+ hn = gethostname_malloc();
+ if (!hn)
+ return -ENOMEM;
+ if (!username) {
+ un = getlogname_malloc();
+ if (!un)
+ return -ENOMEM;
+ }
+
+ if (!origin_tty) {
+ (void) getttyname_harder(STDIN_FILENO, &stdin_tty);
+ origin_tty = stdin_tty;
+ }
+
+ if (asprintf(&text,
+ "\r\n"
+ "Broadcast message from %s@%s%s%s (%s):\r\n\r\n"
+ "%s\r\n\r\n",
+ un ?: username, hn,
+ origin_tty ? " on " : "", strempty(origin_tty),
+ FORMAT_TIMESTAMP(now(CLOCK_REALTIME)),
+ message) < 0)
+ return -ENOMEM;
+
+ return do_wall(text, username, origin_tty, match_tty, userdata);
+}
diff --git a/src/shared/wall.h b/src/shared/wall.h
new file mode 100644
index 0000000000..4423c39404
--- /dev/null
+++ b/src/shared/wall.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdbool.h>
+
+int wall(
+ const char *message,
+ const char *username,
+ const char *origin_tty,
+ bool (*match_tty)(const char *tty, bool is_local, void *userdata),
+ void *userdata);
diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c
index 46d2307ad3..87c610bc73 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -41,7 +41,7 @@
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
-#include "utmp-wtmp.h"
+#include "wall.h"
static enum {
ACTION_LIST,
@@ -216,16 +216,16 @@ static int process_one_password_file(const char *filename) {
return 0;
case ACTION_WALL: {
- _cleanup_free_ char *wall = NULL;
+ _cleanup_free_ char *msg = NULL;
- if (asprintf(&wall,
+ if (asprintf(&msg,
"Password entry required for \'%s\' (PID " PID_FMT ").\r\n"
"Please enter password with the systemd-tty-ask-password-agent tool.",
strna(message),
pid) < 0)
return log_oom();
- (void) utmp_wall(wall, NULL, NULL, wall_tty_match, NULL);
+ (void) wall(msg, NULL, NULL, wall_tty_match, NULL);
return 0;
}
case ACTION_QUERY:
diff --git a/test/README.testsuite b/test/README.testsuite
index c0f1a2b102..bd72f413d0 100644
--- a/test/README.testsuite
+++ b/test/README.testsuite
@@ -191,7 +191,7 @@ the PR (set by the $UPSTREAM_PULL_REQUEST env variable) you'd like to debug:
Now install necessary build & test dependencies:
## PPA with some newer Ubuntu packages required by upstream systemd
-# add-apt-repository -y ppa:upstream-systemd-ci/systemd-ci
+# add-apt-repository -y --enable-source ppa:upstream-systemd-ci/systemd-ci
# apt build-dep -y systemd
# apt install -y autopkgtest debhelper genisoimage git qemu-system-x86