Commit Graph
60990 Commits
Author SHA1 Message Date
Yu Watanabe a74b3e1778 dlopen-note: move all dlopen notes to dlopen-note.h
This also switches all these notes to be defined via SD_ELF_NOTE_DLOPEN_ANCHORED().
Consequently, any notes added within unreachable or unused functions will be
automatically garbage-collected by the linker (--gc-sections) instead of
bloating the final binary.

E.g. unused p11-kit library dependency is now dropped from
systemd-repart.standalone binary.

Before:
```
$ systemd-analyze dlopen-metadata build/systemd-repart.standalone
FEATURE    DESCRIPTION                                                SONAME                        PRIORITY
cryptsetup Support for disk encryption, integrity, and authentication libcryptsetup.so.12           recommended
blkid      Support for block device identification                    libblkid.so.1                 required
libcrypto  Support for cryptographic operations                       libcrypto.so.4 libcrypto.so.3 recommended
mount      Support for mount enumeration                              libmount.so.1                 required
fdisk      Support for reading and writing partition tables           libfdisk.so.1                 required
blkid      Support for block device identification                    libblkid.so.1                 recommended
libcrypto  Support for cryptographic operations                       libcrypto.so.4 libcrypto.so.3 suggested
cryptsetup Support for disk encryption, integrity, and authentication libcryptsetup.so.12           suggested
fdisk      Support for reading and writing partition tables           libfdisk.so.1                 suggested
idn        Support for internationalized domain names                 libidn2.so.0                  suggested
mount      Support for mount enumeration                              libmount.so.1                 recommended
selinux    Support for SELinux                                        libselinux.so.1               recommended
tpm        Support for TPM                                            libtss2-esys.so.0             suggested
tpm        Support for TPM                                            libtss2-rc.so.0               suggested
tpm        Support for TPM                                            libtss2-mu.so.0               suggested
tpm        Support for TPM                                            libtss2-tcti-device.so.0      suggested
p11-kit    Support for PKCS11 hardware tokens                         libp11-kit.so.0               suggested
```

After:
```
$ systemd-analyze dlopen-metadata build/systemd-repart.standalone
FEATURE    DESCRIPTION                                                SONAME                        PRIORITY
cryptsetup Support for disk encryption, integrity, and authentication libcryptsetup.so.12           recommended
blkid      Support for block device identification                    libblkid.so.1                 required
libcrypto  Support for cryptographic operations                       libcrypto.so.4 libcrypto.so.3 recommended
mount      Support for mount enumeration                              libmount.so.1                 required
fdisk      Support for reading and writing partition tables           libfdisk.so.1                 required
blkid      Support for block device identification                    libblkid.so.1                 recommended
libcrypto  Support for cryptographic operations                       libcrypto.so.4 libcrypto.so.3 suggested
cryptsetup Support for disk encryption, integrity, and authentication libcryptsetup.so.12           suggested
fdisk      Support for reading and writing partition tables           libfdisk.so.1                 suggested
mount      Support for mount enumeration                              libmount.so.1                 recommended
selinux    Support for SELinux                                        libselinux.so.1               recommended
tpm        Support for TPM                                            libtss2-esys.so.0             suggested
tpm        Support for TPM                                            libtss2-rc.so.0               suggested
tpm        Support for TPM                                            libtss2-mu.so.0               suggested
tpm        Support for TPM                                            libtss2-tcti-device.so.0      suggested
```
2026-07-10 16:34:26 +09:00
Yu Watanabe aa0db003cf sd-dlopen: introduce SD_ELF_NOTE_DLOPEN_ANCHORED() macro
SD_ELF_NOTE_DLOPEN_ANCHORED() emits a .note.dlopen ELF note that is
"anchored" to a dummy symbol via the SHF_LINK_ORDER ('o') section flag,
in addition to SHF_GROUP ('G') for folding identical notes together.

Unlike the plain SD_ELF_NOTE_DLOPEN() macro, this variant ties the
note's lifetime to a dummy symbol named with the specified tag: if the
linker's --gc-sections removes the function that calls the macro (e.g.
because the function is never referenced), the associated .note.dlopen
entry is garbage-collected along with it.

Currently, the new macro is unused in our code, but all dlopen notes
will be generated with this in later commits.
2026-07-10 16:29:54 +09:00
Yu Watanabe 19d562b0be test: drop explicit dlopen notes from test executables
Typically, we do not explicitly set dlopen note on test binaries.

If we should set notes, let's do that consistently later.
2026-07-10 16:29:54 +09:00
Yu Watanabe 0740a5f1c7 bpf-util: merge two dlopen_bpf() declaration
No functional change. Just for consistency with other dlopen_libfoo().
2026-07-10 16:29:54 +09:00
Yu Watanabe 39d00e1d20 meson: support building .standalone variants for shared modules
Extend the module building logic to automatically generate '.standalone'
variants for non-NSS/PAM shared modules (such as cryptsetup tokens).

Like standalone executables, these are not built by default to keep
the base build time unaffected, but can be built explicitly on demand
via `ninja <module_name>.standalone`.
2026-07-10 16:29:54 +09:00
Yu Watanabe 1f76654f94 meson: automate .standalone variant generation via extended 'install' field
Extend the 'install' keyword for executable definitions to accept four
modes—'yes', 'no', 'both', and 'static'—to elegantly manage the creation
and installation of both shared and statically-linked (.standalone) binaries.

- 'yes' / 'no': Standard behavior (mapped to true/false).
- 'both': Installs both the shared and static variants.
- 'static': Installs the static variant under the original name, while
  suffixing the uninstalled shared variant with '.shared'.

With this change, any arbitrary executable can now have its `.standalone`
variant built on demand simply by invoking `ninja <target>.standalone`.
For example, `varlinkctl` did not previously support a standalone variant,
but it can now be built explicitly via `ninja varlinkctl.standalone`.

These `.standalone` binaries are not built by default unless explicitly
specified as a ninja target or enabled via `-Dstandalone-binaries=true`.
Thus, the default build time should remain unaffected.

This centralisation eliminates a massive amount of boilerplate and duplicated
target declarations across almost all subdirectories (e.g., systemd-repart,
systemd-tmpfiles, systemd-shutdown, and systemd-report tools).
2026-07-10 16:29:53 +09:00
Yu Watanabe 4bda7547f4 import: drop redundant oci-util.c from sources
It is already listed in the 'export' field.
2026-07-10 16:29:53 +09:00
Yu Watanabe e9dd6f6dc4 dns-configuration: make dns_scope_free() static
systemd-resolved already has a dns_scope_free() function in
resolved-dns-scope.c for DnsScope. Since the one in dns-configuration.c
is only used internally, make it static.

This is necessary to allow systemd-resolved to be statically linked
with libsystemd-shared without symbol conflicts.
2026-07-10 16:29:53 +09:00
Kai Lüke 70cd612797 creds: Use ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR
The error set was duplicated, use the macro.
2026-07-10 08:07:47 +02:00
Kai Lüke e2b89bc3d5 cryptsetup: Give NV index missing its own error code
To be able to continue trying other tokens to unlock a disk the missing
NV index case was mapped to EREMOTE (foreign TPM) which was ok because
this mostly happens when trying to unlock on another system. Still it
might be useful to deal with NV index errors differently.
Give it its own EADDRNOTAVAIL error and handle it at all call sites.
2026-07-10 08:07:47 +02:00
Kai Lüke 7fb6b9c2a2 cryptsetup: Skip tokens with JSON parsing errors
The plugin already continues on parsing errors but the fallback path
not. The plugin swallows ENOMEM as well which is too much, though.
Continue on JSON parsing errors by mapping them to EUCLEAN in
cryptsetup_get_token_as_json and handle that in any call site, not just
the TPM fallback path but also others.
2026-07-10 08:07:47 +02:00
Kai Lüke 14c0b8414f cryptsetup: Reduce log level for TPM mismatches
When we iterate over tokens we should not print mismatches as errors
but rather warnings. At the end there is still a summary with the
notice level (gated by found_some) which the user can relate to the
warnings.
2026-07-10 08:07:47 +02:00
Kai Lüke d09e025b85 cryptsetup: Remap bad PCR set early to EPERM
Currently libcryptsetup's look treats ENOANO special because it's used
to signal PIN requirement. But the bad PCR set can also contain ENOANO
for a mismatch from a PolicyOR branch.
To continue iterating, remap the bad PCR set to EPERM early. This would
in theory also allow us to simplify the matching for the iteration
condition but we leave this as is for now to prevent a future
regression.
2026-07-10 08:07:47 +02:00
Kai Lüke 0f1ee40986 tpm2-util: Also report EREMOTE if key is for different parent template
We already report foreign TPM keys (wrapped for different parent) but
this is not enough because when also a different template was used, we
don't get TPM2_RC_INTEGRITY but TPM2_RC_SIZE.
Also cover TPM2_RC_SIZE to report EREMOTE so that we can continue to
iterate over LUKS tokens instead of giving up.
2026-07-10 08:07:47 +02:00
Kai Lüke ac5f02cc76 tpm2-util: For NV index errors report EREMOTE to be able to continue
When we have many LUKS slots and not all are for our TPM, we can get an
NV index error when it's missing or has wrong content.
Instead of fully erroring out, map these encounters to EREMOTE like we
do for a foreign TPM key.
2026-07-10 08:07:47 +02:00
Kai Lüke 93bc6a3415 tpm2-util: Align tpm2_import with tpm2_load to report on foreign keys
When we encounter a key for a foreign TPM we report that as EREMOTE in
tpm2_load but not yet in tpm2_import. This causes cryptsetup to give up
on using the TPM instead of being able to continue with out tokens.
Do the same mapping as in tpm2_load in tpm2_import to report EREMOTE on
foreign keys.
2026-07-10 08:07:47 +02:00
Kai Lüke 9213de2e06 cryptsetup/cryptenroll: Iterate over TPM tokens when they don't match
When we enroll two UKIs with different PCR pub keys into one LUKS slot/
token each, then we can encounter the wrong one and should not give up
but continue iterating instead of requiring the passphrase. Similarly,
a pcrlock token might be for another UKI and we should continue the
search. Same for a token that is meant for another TPM (e.g., external
storage). While this is mainly about cryptsetup's automatic unlocking
from the initrd, it also matters for usage in the system, e.g., for
other storage and when cryptenroll should unlock using the TPM.
There are two code paths, one is the libcryptsetup plugin and the other
is the fallback when that's not available.
To let the libcryptsetup loop continue to iterate, remap the above
error conditions to EPERM. For the fallback path check all of them (no
remapping) and continue iteration. For better log output, include the
token ID to be able understand which token fails.
2026-07-10 08:07:47 +02:00
Kai Lüke 58d38f6360 cryptsetup: Report mismatching TPM token error separately
When we enroll two UKIs with different PCR pub keys into one LUKS slot/
token each, then we can encounter the wrong one and should report it
with a clearer error than the generic "Failed to unseal secret using
TPM2".
So when we don't have the right signature, report this as separate
error.
2026-07-10 08:07:47 +02:00
Kai Lüke 924552cfba stub: Set up all detected consoles
With no console= given the kernel will use the graphical console and if
we give one console= then that will be used instead. But sometimes we
want both a serial console and a graphical one to work. This would be
consistent with the EFI menu and sd-boot showing on both already. It
also makes the impact of a wrongly detected-but-missing VirtIO console
lower when we emit it alongside of the other consoles we detect.

Collect all detected consoles and emit them via console= with the same
priority we used before to select them. This means for the main console
there is no change but we get additional ones enabled. This helps with
boot output and having a login presented, yet the main console is still
special and gets the emergency output at boot (we should somehow surface
that on the additional consoles but that's another topic). If we only
see the graphical console (or none), we don't need to emit anything a
the kernel already selects it itself. This also avoids suppressing the
non-x86 kernel serial console detection. As mentioned above, the VirtIO
console being wrongly added is now also less impactful. But for non-x86
ACPI case we could detect the serial so that console=hvc0 won't stop the
kernel serial auto-detection.
2026-07-10 03:36:04 +02:00
Kai Lüke f6a7a9ec3d mount-util/sysext: Clone sub mounts as private to preserve nested ones
When nested mounts appear under a sysext hierarchy like this:
  mkdir -p /opt/trigger/
  mount -t tmpfs tmpfs /opt/trigger
  mkdir -p /opt/trigger/inner
  mount -t tmpfs tmpfs /opt/trigger/inner
Then systemd-sysext merge will lose the inner mount because it uses a
regular bind mount with propagation and then unmounts the source,
unmounting all children with it which propagates (as found out in
https://github.com/flatcar/Flatcar/issues/2111).
To solve this, clone the sub mount with MS_PRIVATE to decouple sub
mounts from the original mount. Then attach the cloned mount instead of
doing regular bind mounts. For old kernels we still attach the cloned
mount but we fallback to cloning without MS_PRIVATE. This change also
affects mount_private_apivfs which is used for private /proc, /sys, and
cgroupfs but I think it makes sense there, too, instead of only doing
mount_setattr for sysext alone because, e.g., a container and the host
should not be leaking mount actions into each other for these mounts.
2026-07-10 03:34:54 +02:00
Kai Lüke 7eabeaed0e mount-util: Compact list of sub mounts after dropping
When nested mounts appear under a sysext hierarchy like this:
  mkdir -p /opt/trigger/
  mount -t tmpfs tmpfs /opt/trigger
  mkdir -p /opt/trigger/inner
  mount -t tmpfs tmpfs /opt/trigger/inner
Then systemd-sysext merge hit an assertion reported in
https://github.com/flatcar/Flatcar/issues/2111 because when it iterates
over the list of sub mounts it doesn't expect entries with NULL in the
path from the dropped entries.
Instead of having to deal with entries with path NULL, better sort the
holes from dropping to the end and then reduce the array length.
2026-07-10 03:34:54 +02:00
dongshengyuan add910a838 sysupdate: handle slashes after pattern fields
Patterns such as foo_@v/bar.efi are documented to
match files in versioned subdirectories,
but pattern_match() assumed that a field is
always followed by a literal when another element exists.

Handle a following slash as a delimiter too,
and request another recursion step
when the current path ends before that slash.

Fixes #42895.
Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
2026-07-09 14:36:36 +02:00
Michael Vogt c944af8459 tree-wide: fix some double word errors like "the the"
By chance (because I had this mistake in my own commit) I noticed
that there are a bunch of duplicated works like "the the" in the
code and man-pages.

This commit fixes them and some similar issues with "and and" etc.
2026-07-09 13:09:52 +01:00
dongshengyuan 944b160007 core: connect to sockets in credential directories
Recursive credential directory loading intentionally
includes socket entries, but load_credential()
only enabled AF_UNIX socket handling for absolute paths.

Let the recursive directory path request socket
connections explicitly, and update the stale comment for directory-fd reads.

Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
2026-07-09 13:34:33 +02:00
Lennart Poettering fb15860051 sysupdate: load a per-component *.component file (#42935)
This is split out of #42651, because for some reason Claude refuses to
review that PR, probably because it's too large. Hence let's try this
piecemeal.

This has integration tests in #42651 (which passed). And docs too.
2026-07-09 12:21:28 +02:00
Lennart Poettering 9c21e058d1 Assorted logind hardening fixes flagged by kres (#42879) 2026-07-09 11:07:06 +02:00
dongshengyuan 8cbae52fc9 pcrlock: handle piped PE input
When lock-pe or lock-uki read from stdin,
copy non-regular input to a seekable temporary fd before hashing it.

Fixes #42893.
Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
2026-07-09 11:02:46 +02:00
dongshengyuan 4839cb914e dissect: do not follow copy-to directory symlinks
When copying a directory into an image, open an existing destination
with O_NOFOLLOW before passing it to copy_tree_at(). This rejects a
symlink used as the final destination component without a separate
stat-before-use check.

Previously the pre-opened destination followed that symlink. That
allowed --copy-to to be redirected outside the image root when the
image was a directory tree.

If the destination does not exist yet, keep delegating creation to
copy_tree_at(). Real existing directories still use COPY_MERGE through
the opened directory fd.

Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
2026-07-09 11:01:29 +02:00
Lennart Poettering 04915e3d37 Assorted coverity fixes (#42933) 2026-07-09 11:01:03 +02:00
Lennart Poettering af8700527a shared: fix DNS RR wire cache and EFI boot option bounds checks (#42926)
Invalidate cached DNS RR wire format when
`dns_resource_record_clamp_ttl()` updates `rr->ttl` in place.
Validate each EFI `Boot####` device-path node length before reading
subtype-specific fields.
2026-07-09 11:00:29 +02:00
Lennart Poettering 5f44e242ae Assorted journal/portable hardening fixes flagged by kres (#42915) 2026-07-09 10:59:02 +02:00
Lennart Poettering 76c697f1fb journal-remote: do not create /var/log/journal/remote (#42937)
This handling with tmpfiles was dropped in
29444df23b. So let's stop the build system
to create that directory. Actually it is create by the service just
fine, including correct access mode.
2026-07-09 10:55:13 +02:00
Kai Lüke 2f76050c5c stub: Prefer graphical console over virtio detection heuristic
With vmspawn --console=gui and similar one has the case where the VirtIO
PCI device is present for something else than the console and the logic
in sd-stub added console=hvc0 even though it didn't exist. This caused
tty0 to be empty during boot.
Always prefer the graphical console before a potential virtio console.
The virtio console is still preferred over a serial console and we can
get the same problem there, e.g., qemu-guest-agent is used causing the
PCI device but without a virtio console and instead a serial console is
used. This is not solved here.
2026-07-09 10:54:52 +02:00
countgitmick ce043cdfdb logind: set session->started before seat_read_active_vt() call
session_start() calls seat_read_active_vt() before setting
s->started = true. seat_read_active_vt() can reach
seat_triggered_uevents_done() synchronously via:

  seat_active_vt_changed -> seat_set_active -> seat_trigger_devices
  -> seat_triggered_uevents_done

When seat_trigger_devices() produces no pending uevents,
seat_triggered_uevents_done() runs in the same call stack as
session_start() and tests session->started before the assignment
further down. The check fails, session_device_resume_all() is
skipped, and the compositor never receives DRM master.

Set started before seat_read_active_vt() so the gate sees the
correct value, and document the ordering constraint at the call
site to prevent regression.

Reproducible with greetd plus a Wayland compositor on the same VT
on kernel 6.19+.

Fixes: #41562
Signed-off-by: countgitmick <263313427+countgitmick@users.noreply.github.com>
2026-07-09 10:17:46 +02:00
Lennart Poettering 2a438fdea2 sysupdate: show component description and enablement in 'systemd-sysupdate components' call
This is losely based on the features output, but shows the new metadata
for components.
2026-07-09 09:56:48 +02:00
Lennart Poettering 291e6118f5 sysupdate: optionally load a per-component *.component file
This file can be used for metadata about a component. It may also be
used to "disable" a component.

This brings components as a concept to a similar conceptual level as
features: both can be enabled/disabled, and carry metadata
2026-07-09 09:56:48 +02:00
Christian Hesse fc99dc4c42 journal-remote: do not create /var/log/journal/remote
This handling with tmpfiles was dropped in
29444df23b. So let's stop the build system
to create that directory. Actually it is create by the service just
fine, including correct access mode.
2026-07-09 09:09:34 +02:00
dongshengyuan d13b002aec efi-api: validate boot option device path lengths
efi_get_boot_option() validates the overall Boot#### variable size and
the advertised device-path byte count, but then walks each device-path
node without first checking that the node header and subtype payload fit
in the remaining buffer.

A malformed Boot#### variable could make the parser read past the end of
the current node, or past the available device-path data.

Limit parsing to the bytes that are actually present, and stop walking
the device path when a malformed node is encountered. This keeps the
previous best-effort behaviour for fields parsed before the anomaly while
avoiding out-of-bounds reads.

Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
2026-07-09 08:39:03 +08:00
dongshengyuan ccae5c7a4f dns-rr: invalidate wire format after changing ttl
dns_resource_record_clamp_ttl() may patch the TTL in place when the
record has a single reference. dnssec_fix_rrset_ttl() also updates TTLs
after canonical wire-format data may have been cached.

If a record already has cached wire-format data, that cache still
contains the old TTL and dns_resource_record_to_wire_format() will keep
reusing it.

Add a small helper to clear the cached wire-format state, and use it
whenever the TTL changes. This makes subsequent serialization match the
record fields.

Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
2026-07-09 08:35:03 +08:00
Andres Beltran 001c5dfdf5 tmpfiles: add hardening in glob_item_recursively 2026-07-08 22:50:55 +01:00
Michal Sekletar c5b508b0c7 socket-util: fix socket_xattr_supported() in initramfs
Don't test xattr support on socket created in filesystem. This doesn't
work in initramfs when /tmp doesn't have tmpfs mounted inside as
initramfs doesn't have xattr support. Setting socket xattr falls back to
parent directory xattr handlers when we work with FS based socket.

Let's test sockfs based socket instead so that the check is generic and
works in all environments.
2026-07-08 17:54:27 +01:00
Luca Boccassi 052ff5fb5d resolved: honour per-link DNSOverTLS=yes for certificate verification
dnstls_stream_connect_tls() reads the manager-wide dns_over_tls_mode
field directly, so when the global mode was 'no' or 'opportunistic' but
a link was configured with strict DNSOverTLS=yes, the DoT connection
was established without SSL_VERIFY_PEER or hostname/IP checks.
Use dns_server_get_dns_over_tls_mode() which honours the per-link
override.
2026-07-08 17:29:03 +02:00
Luca Boccassi feda6f31d8 pcrlock: add vl method for list-components
Add varlink method wrapper for list-components verb.
2026-07-08 16:22:05 +01:00
Frantisek Sumsal 9ae50c78cc sd-event: use CLOCK_BOOTTIME for rate limits
When a rate limit is armed, for example via StartLimitInterval=, and the
machine is suspended, the rate limit's "clock" is suspended as well,
since the elapse checks use CLOCK_MONOTONIC. This then causes unexpected
situations where a rate limit armed via StartLimitInterval=1h, followed
by a 10 hour suspend, would elapse after 11 hours total.

Let's avoid this by switching the rate limits to CLOCK_BOOTTIME, which
works the same as CLOCK_MONOTONIC, but accounts for the time spent in
suspend as well.

There's one slight concern when it comes to upgrade path - the old
"begin" value of the rate limit is stored as CLOCK_MONOTONIC, but after
upgrading systemd and serializing/deserializing the state it will be
suddenly compared against now(CLOCK_BOOTTIME), which might cause some
rate limits to elapse "prematurely". But this is just a one-time thing,
after which the rate limit timers should re-assess themselves.

Resolves: #42912
2026-07-08 15:38:39 +01:00
Lương Việt Hoàng 0168b13fb3 creds-util: log when we remove a secret from a different machine 2026-07-08 14:49:14 +01:00
Luca Boccassi 7967b6b6d5 sd-device: check fd validity before using in sendmsg in test
CID#1663676

Follow-up for 7003a9bf09
2026-07-08 13:36:32 +01:00
dongshengyuan 34a2223344 dns-rr: fix SOA JSON fields
Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
2026-07-08 13:03:23 +01:00
dongshengyuan da9a330dfd fsck: don't apply invalid mode or repair values
fsck_mode_from_string() and fsck_repair_from_string() return -EINVAL
on a bad value. Store the result in a local variable first, and only
update the global state on success.

Otherwise an invalid value is logged as ignored, but still leaves a
negative enum value behind. In the fsck.repair case that makes
fsck_repair_option_to_string() return NULL and truncates the fsck
command line.

Follow-up for a85428b1d3
Follow-up for 059afcadfd

Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
2026-07-08 12:13:43 +01:00
Elliot Berman 1b03303998 bootctl: Fix prepend when installing systemd-boot for the first time
In commit 38433a6d06 ("bootctl: rework bootctl-install.c in preparation of varlinkification"),
the `first` argument of install_boot_option() was reworked to use the
new InstallContext struct/InstallOperation. `first` was intended to
indicate if we were on the install path, so the check should be
== INSTALL_NEW, not != INSTALL_NEW.

Fixes: 38433a6d06 ("bootctl: rework bootctl-install.c in preparation of varlinkification")
2026-07-08 11:06:42 +01:00
Luca Boccassi 6248f1b774 sd-bus: voidify bus_match_remove call
It cannot fail, just returns 0 or 1 for not found/found

CID#1663675
2026-07-08 10:54:04 +01:00