1
0
mirror of https://github.com/systemd/systemd synced 2026-03-25 00:04:53 +01:00

Compare commits

...

18 Commits

Author SHA1 Message Date
Luca Boccassi
9e418cd075
inhibit: allow filtering and add --json support for --list (#39973) 2025-12-18 10:47:23 +00:00
Luca Boccassi
9a34971421 fido2: fix enrolling when UV is required ('alwaysUv')
When a Yubikey or other fido2 device has FIPS mode enabled, UV will
always be required and cannot be disabled. Unhelpfully, when it is not
sent down, the hardware token (not the library) returns a generic
FIDO_ERR_MISSING_PARAMETER:

$ systemd-cryptenroll --fido2-device=auto --fido2-with-client-pin=no foo
<...>
libfido2: rx: payload_len=1
libfido2: fido_rx: buf=0x55c9ce170940, len=1
libfido2: 0000: 14
libfido2: cbor_parse_reply: blob[0]=0x14
libfido2: fido_dev_get_assert_rx: adjust_assert_count
Failed to ask token for assertion: FIDO_ERR_MISSING_PARAMETER

This can be set even when the token doesn't support UV (as in, fingerprint
reader), in which case using the PIN is required.

Check if 'alwaysUv' is set, and if not already configured, force
either UV (if available) or PIN when enrolling.
2025-12-18 10:56:43 +01:00
Jeremy Kerr
cc1ed77280 udev-builtin-net_id: Extend persistent naming support to MCTP interfaces
Now that we have Management Component Transport Protocol (MCTP) transports
available over USB, it would be helpful to apply udev's persistent
naming rules to MCTP interfaces, to follow the USB hub/port topology.

Enable persistent naming for ARPHRD_MCTP-type devices, using a "mc" name
prefix, and add appropriate definitions for the v260 naming sheme.
2025-12-18 10:54:51 +01:00
Popax21
f603bc37f4 nss-resolve: add env var to specify resolved ifindex
Adds a new `SYSTEMD_NSS_RESOLVE_INTERFACE` environment variable to the nss-resolve module, whose value is subsequently passed down to the `ifindex` resolved lookup option.
This allows name lookups to be constrained to a just single interface for e.g. captive portal browsers.
2025-12-18 10:53:27 +01:00
Lennart Poettering
18d90c1628 bash: clarfiy what 80-systemd-osc-context.sh is about in the spec 2025-12-18 10:50:23 +01:00
Lennart Poettering
d91aed3b55 docs: add redirection of the osc context to uapi website 2025-12-18 10:50:23 +01:00
Luca Boccassi
f33d550d44
Add polkit support to varlinkctl and sd-sysext (#39796) 2025-12-18 09:10:53 +00:00
Daan De Meyer
27aba70b3b
core: two trivial cleanups (#40126)
Split out from #40093
2025-12-18 08:55:29 +01:00
Daan De Meyer
198898c07b
docs: some updates to release process (#40128) 2025-12-18 08:53:43 +01:00
Luca Boccassi
cb6ccb1c31 mkosi: update debian commit reference to 6f15bdaae7014c233b662ac4a33d464893b81b36
* 6f15bdaae7 Update architecture match for 50-pid-max.conf (v3)
* 333cc1fcc5 Downgrade depends to recommends for IPC endpoint of respective libnss modules
* ab99a1b51a Revert "Update architecture match for 50-pid-max.conf"
* b93d7f855a Update changelog for 259~rc3-1 release
* 95c7f8a3d6 Install new udev rule
* 89509d9692 d/t/tests-in-lxd: re-construct --pin-packages arguments for autopkgtest
* 6b77249c71 d/extra/dbus-1: rename systemd-localed-read-only.conf
* 819831c19a Update architecture match for 50-pid-max.conf
* 0ddff89e9d Mirror dmi_arches from meson.build into debian/udev.install
* 398e8791db d/t/control: pull in optional libs for boot-and-services too
* c727922ad5 Update changelog for 259~rc2-1 release
* 8faf105531 Install new varlinkctl bash completion script
* f4b4cea2be d/t/control: ensure unit-tests autopkgtest pulls in dlopened libraries for test
* 7e8aba9883 Update changelog for 259~rc1-1 release
* 5953c42402 Update symbols file for v259~rc1
* 353125ccfa Install new files for v259~rc1
* ca22d1ca4f Drop patches, all merged upstream
* 32c75efca2 d/t/unit-config: fix python decorator copypasta
* e32179d633 d/rules: disable sysv compat in upstream builds
* cf77bd44be Install new files for upstream build
* aa564e5d3b kernel-install: skip 55-initrd.install when an initrd is already staged
2025-12-18 08:53:03 +01:00
Luca Boccassi
ea73b8887b docs: update mkosi config file path in release process
Follow-up for fb514c2f8f195c869b2f0e9ea5ae4ecdd639ebbd
2025-12-18 00:47:14 +00:00
Luca Boccassi
b1192a01cd docs: add OBS step to release process
Version rewriting in obs-service-tar-scm is not happy with rc tags
2025-12-18 00:46:41 +00:00
Mike Yuan
16bae207c2
core/dbus-execute: respect write flags for empty assignments too 2025-12-18 00:39:59 +01:00
Mike Yuan
8619c65fcf
core/service: const and pure'ify service_restart_usec_next() 2025-12-18 00:39:59 +01:00
Antonio Alvarez Feijoo
2824182a12 inhibit: allow filtering --list also by what, who and why
Currently the list can only be filtered by mode, so make use of the remaining
options available to filter the output.
2025-12-17 23:23:44 +00:00
Antonio Alvarez Feijoo
c40ab2337f inhibit: add --json support for --list 2025-12-17 23:23:44 +00:00
Luca Boccassi
34f41471fc sysext: add polkit support to varlink service 2025-12-17 23:22:05 +00:00
Luca Boccassi
a2d53619c0 varlinkctl: add support for polkit interactive auth 2025-12-17 23:22:05 +00:00
26 changed files with 399 additions and 425 deletions

View File

@ -1,339 +1 @@
---
title: OSC 3008: Hierarchical Context Signalling
category: Interfaces
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# OSC 3008: Hierarchical Context Signalling
A terminal connects a user with programs. Control of the program side of
terminals is typically passed around to various different components while the
user is active: a shell might pass control to a process it invokes. If that
process is `run0` then primary control is passed to the privileged session of
the target user. If `systemd-nspawn` is invoked to start a container, primary
control is passed to that container, and so on.
A terminal emulator might be interested to know which component is currently in
primary control of the program side of a terminal. OSC 3008 is a mechanism to
inform it about such contexts. Each component taking over control can inform
the terminal emulators that a new context begins now, and then use the terminal
or pass control down to further apps, which can introduce contexts. Each
context may carry various descriptive metadata fields.
## Status
This OSC sequence has been invented by the systemd project and is generated by
systemd. Currently, no terminal application is known that consumes these
sequences.
## Use Cases
Terminal emulators can use hierarchical context information:
1. To introduce markers/bookmarks in the output that the user can jump between.
2. To visually identify output from different contexts. For example the
background of the associated output can be tinted in a reddish tone when
privileges are acquired, and similar.
3. Meta information on specific output can be shown in a tooltip or similar
4. Programs (and all subcontexts) can be killed via a right-click menu on the
output they generate.
5. Similar, a right-click menu might offer an item to offer opening a new
interactive shell in the same working directory that was current on the
selected context.
6. Failed commands or aborted sessions can be marked requesting user attention.
## Context Types
There are various types of contexts defined by this specification:
1. `boot` → a booted system initiates this context early at boot. (systemd's
PID 1 generates this on `/dev/console`.)
2. `container` → a container manager initialized an interactive connection to a
container. (`systemd-nspawn` generates this when interactively invoking a
container. `machinectl login`, `machinectl shell` do this too.)
3. `vm` → a VM manager initialized a terminal connection to a
VM. (`systemd-vmspawn` generates this when interactively invoking a VM, as
one example.)
4. `elevate` → when the user interactively acquired higher privileges. (`run0`
initiates a context of this type whenever the user invokes it to acquire
root privileges.)
5. `chpriv` → similar, but when the user acquired *different* privileges, not
necessarily higher ones. (`run0` initiates a context of this type whenever
the user invokes it to acquire non-root privileges of another user.)
5. `subcontext` → similar, but the source and target privileges where
identical. (`run0` initiates a context of this type whenever the user
invokes it to acquire privileges of the user itself.)
6. `remote` → a user invoked a tool such as `ssh` to connect to a remote
system.
7. `shell` → an interactive terminal shell initiates this context
8. `command` → a shell interactively invokes a new program.
9. `app` → an interactive program may initiate this context.
10. `service` → the service manager invokes an interactive service on the terminal
11. `session` → a login session of the user is initialized.
## Semantics
Contexts in the sense of OSC 3008 are hierarchical, and describe a tree
structure: whenever a new context is opened it becomes the new active context,
and the previously active context becomes its parent (if there is one). Only
one context is currently active, but previously opened contexts remain valid in
the background. Any other data written or read should be considered associated
with the currently active context.
Each context carries an identifier, chosen by the component opening the
context. The identifier can chosen freely, but must not be longer than 64
characters. The characters may be in the 32…126 byte range. Identifiers should
be universally unique, for example randomly generated. A freshly generated UUID
would work well for this, but this could also be something like the Linux boot
ID combined with the 64bit inode number of Linux pidfds, or something hashed
from it.
Fundamentally, there are two OSC 3008 commands defined:
1. OSC "`3008;start=`" … (the *start sequence*) → this initiates, updates or
indicates a return to a context. It carries a context identifier, and
typically some metadata. This may be sent to first initiate a context. If
sent again for the same context ID that was initiated already this indicates
an update of the existing context. In this case, *any* previously set
metadata fields for the context are flushed out, reset to their defaults,
and then reinitialized from the newly supplied data. Also, in this case any
subcontexts of the contexts are implicitly terminated.
2. OSC "`3008;end=`" … (the *end sequence*) → this terminates a context. It
carries a context identifier to close, initiated before with OSC
"`3008;start=`". It may also carry additional metadata.
## General Syntax
This builds on ECMA-48, and reuses the OSC and ST concepts introduced there.
For sequences following this specification it is recommended to encode OSC as
0x1B 0x5D, and ST as 0x1B 0x5C.
ECMA-48 only allows characters from the range 0x20…0x7e (i.e. 32…126) inside
OSC sequences. However, most terminal emulators nowadays allow the ASCII byte
range > 0x7f in the OSC sequences they process, and so does this
specification. Control characters (< 0x20 and 0x7f) are not allowed. The
semicolon character ("`;`") which is used as field separator by this
specification shall be replaced by "`\x3b`" and the backslash character
("`\`") shall be replaced by "`\x5c`". All textual fields must be encoded in
UTF-8, and then escaped with these two replacements.
The start sequence begins with OSC, followed by the string `3008;start=`,
followed by the context ID. This is then followed by any number of metadata
fields, including none. Metadata fields begin with a semicolon (`;`) followed
by in a string identifying the type of field, followed by an equal sign (`=`),
and the field value. The sequence ends in ST.
The end sequence begins with OSC, followed by the string `3008;end=`, followed
by the context ID, and a series of metadata fields in the same syntax as for
the start sequence. The sequence ends in ST.
## Metadata Fields
The following fields are currently defined for the start sequence:
| Field | Context Types | Description |
|---------------|---------------|-------------------------------------------------------------------------------------------------------------|
| `type=` | *all* | Declares the context type, one of the types described above |
| `user=` | *all* | UNIX user name the process issuing the sequence runs as |
| `hostname=` | *all* | UNIX host name of the system the process issuing the sequence runs on |
| `machineid=` | *all* | The machine ID (i.e. `/etc/machine-id`) of the system the process issuing the sequence runs on |
| `bootid=` | *all* | The boot ID (i.e. `/proc/sys/kernel/random/boot_id`) of the system the process issuing the sequence runs on |
| `pid=` | *all* | The numeric PID of the process issuing the sequence, in decimal notation |
| `pidfdid=` | *all* | The 64bit inode number of the pidfd of the process issuing the sequence, in decimal notation |
| `comm=` | *all* | The process name (i.e. `/proc/$PID/comm`, `PR_GET_NAME`) of the process issuing the sequence |
| `cwd=` | `shell`, `command` | The current working directory |
| `cmdline=` | `command` | The full command line of the invoked command |
| `vm=` | `vm` | The name of the VM being invoked |
| `container=` | `container` | The name of the container being invoked |
| `targetuser=` | `elevate`, `chpriv`, `vm`, `container`, `remote`, `session` | Target UNIX user name |
| `targethost=` | `remote` | Target UNIX, DNS host name, or IP address |
| `sessionid=` | `session` | New allocated session ID |
The following fields are currently defined for the end sequence:
| Field | Context Types | Description |
|---------------|---------------|-------------------------------------------------------------------------------------------------------------|
| `exit=` | `command` | One of `success`, `failure`, `crash`, `interrupt`, indicating how the program terminated |
| `status=` | `command` | The command's numeric exit status, i.e. the 0…255 value a program returns |
| `signal=` | `command` | The termination signal of the command, if it died abnormally. A symbolic signal name. (`SIGKILL`, …) |
All fields are optional, including the context type. However, it is generally
recommended to always include the first 7 fields listed above, to make it easy
to pinpoint the origin of a context in a race-free fashion, without any
ambiguities.
The order of the metadata fields is undefined, they may appear in any order
(including that `type=` is specified at the very end or in the middle!). Note
that `start=` and `end=` are not considered metadata fields but part of the
start sequence, and hence must always appear right after OSC.
## Processing, Limits, Security
All context information provided like this should be considered auxiliary and
to some degree redundant information. Hence, it would be wise for a terminal
to enforce limits on various resources, dropping additional data once these
limits are hit. Most importantly, a maximum stacking depth should probably
enforced: any attempts to initiate further contexts should be ignored once the
stack limit is hit (i.e. the earlier contexts should be kept, the later
contexts be discarded, not the opposite). Overly long fields should be
discarded (or potentially truncated, depending on the field type). This
specification does not recommend any specific stack or string limits for now.
The usual terminal reset sequences should *not* affect the stack of contexts
(this is a safety feature: a program down the stack should not be able to
affect the stack further up, possibly hiding relevant information). A temporary
TTY hangup (`vhangup()`) should result in a full reset of the stack.
All provided data should be processed in a lenient, graceful fashion: if a
sequence contains invalid fields, those fields should be ignored, but the rest
of the fields should still be used. In particular, unknown fields should be
ignored.
The fields provided in these sequences should not contain sensitive
information. Context IDs should not be considered confidential, but it is
strongly recommended to generate them in a fashion that guarantees their
sufficient uniqueness and avoids accidental or intended clashes with other
contents.
## Examples
1. A new container `foobar` has been invoked by user `lennart` on host `zeta`:
`OSC "3008;start=bed86fab93af4328bbed0a1224af6d40;type=container;user=lennart;hostname=zeta;machineid=3deb5353d3ba43d08201c136a47ead7b;bootid=d4a3d0fdf2e24fdea6d971ce73f4fbf2;pid=1062862;pidfdid=1063162;comm=systemd-nspawn;container=foobar" ST`
2. This context ends: `OSC "3008;end=bed86fab93af4328bbed0a1224af6d40" ST`
## Syntax in ABNF
```abnf
OSC = %x1B %x5D
ST = %x1B %x5C
DECIMAL = "0"-"9"
HEX = "0"-"9" / "A"-"F" / "a-f"
ID128 = 32*36(HEX / "-")
UINT64 = 1*20DECIMAL
ESCSEMICOLON = "\x3b"
ESCBACKSLASH = "\x5c"
SAFE = %x20-3a / %x3c-5b / %x5d-7e / ESCSEMICOLON / ESCBACKSLASH
CTXID = 1*64SAFE
TYPEENUM = "service" / "session" / "shell" / "command" / "vm" / "container" / "elevate" / "chpriv" / "subcontext" / "remote" / "boot" / "app"
TYPE = "type=" TYPEENUM
USER = "user=" 1*255SAFE
HOSTNAME = "hostname=" 1*255SAFE
MACHINEID = "machineid=" 1D128
BOOTID = "bootid=" ID128
PID = "pid=" UINT64
PIDFDID = "pidfdid=" UINT64
COMM = "comm=" 1*255SAFE
CWD = "cwd=" 1*255SAFE
CMDLINE = "cmdline=" *255SAFE
VM = "vm=" 1*255SAFE
CONTAINER = "container=" 1*255SAFE
TARGETUSER = "targetuser=" 1*255SAFE
TARGETHOST = "targethost=" 1*255SAFE
SESSIONID = "sessionid=" 1*255SAFE
STARTFIELD = TYPE / USER / HOSTNAME / MACHINEID / BOOTID / PID / PIDFDID / COMM / CWD / CMDLINE / VM / CONTAINER / TARGETUSER / TARGETHOST / SESSIONID
STARTSEQ = OSC "3008;start=" CTXID *(";" STARTFIELD) ST
EXITENUM = "success" / "failure" / "crash" / "interrupt"
SIGNALENUM = "SIGBUS" / "SIGTRAP" / "SIGABRT" / "SIGSEGV" / …
EXIT = "exit=" EXITENUM
STATUS = "status=" UINT64
SIGNAL = "signal=" SIGNALENUM
ENDFIELD = EXIT / STATUS / SIGNAL
ENDSEQ = OSC "3008;end=" CTXID *(";" ENDFIELD) ST
```
## Known OSC Prefixes
Here's a list of OSC prefixes used by the various sequences currently in public
use in various terminal emulators. It's not going to be complete, but I tried
to do some reasonably thorough research to avoid conflicts with the new OSC
sequence defined above.
| OSC Prefix | Purpose |
|----------------:|------------------------------------------------------------|
| `OSC "0;…"` | Icon name + window title |
| `OSC "1;…"` | Icon name |
| `OSC "2;…"` | Window title |
| `OSC "3;…"` | X11 property |
| `OSC "4;…"` | Palette |
| `OSC "5;…"` | Special palette |
| `OSC "6;…"` | Disable special color |
| `OSC "7;…"` | Report cwd |
| `OSC "8;…"` | Hyperlink |
| `OSC "9;…"` | Progress bar (conemu) [conflict: also growl notifications] |
| `OSC "10;…"` | Change colors |
| `OSC "11;…"` | " |
| `OSC "12;…"` | " |
| `OSC "13;…"` | " |
| `OSC "14;…"` | " |
| `OSC "15;…"` | " |
| `OSC "16;…"` | " |
| `OSC "17;…"` | " |
| `OSC "18;…"` | " |
| `OSC "19;…"` | " |
| `OSC "21;…"` | Query colors (kitty) |
| `OSC "22;…"` | Cursor shape |
| `OSC "46;…"` | Log file |
| `OSC "50;…"` | Set font |
| `OSC "51;…"` | Emacs shell |
| `OSC "52;…"` | Manipulate selection data (aka clipboard) |
| `OSC "60;…"` | Query allowed |
| `OSC "61;…"` | Query disallowed |
| `OSC "99;…"` | Notifications (kitty) |
| `OSC "104;…"` | Reset color |
| `OSC "105;…"` | Enable/disable special color |
| `OSC "110;…"` | Reset colors |
| `OSC "111;…"` | " |
| `OSC "112;…"` | " |
| `OSC "113;…"` | " |
| `OSC "114;…"` | " |
| `OSC "115;…"` | " |
| `OSC "116;…"` | " |
| `OSC "117;…"` | " |
| `OSC "118;…"` | " |
| `OSC "119;…"` | " |
| `OSC "133;…"` | Prompt/command begin/command end (finalterm/iterm2) |
| `OSC "440;…"` | Audio (mintty) |
| `OSC "633;…"` | vscode action (Windows Terminal) |
| `OSC "666;…"` | "termprop" (vte) |
| `OSC "701;…"` | Locale (mintty) |
| `OSC "777;…"` | Notification (rxvt) |
| `OSC "3008;…"` | This specification |
| `OSC "7704;…"` | ANSI colors (mintty) |
| `OSC "7750;…"` | Emoji style (mintty) |
| `OSC "7770;…"` | Font size (mintty) |
| `OSC "7771;…"` | Glyph coverage (mintty) |
| `OSC "7721:…"` | Copy window title (mintty) |
| `OSC "7777;…"` | Window size (mintty) |
| `OSC "9001;…"` | Action (Windows Terminal) |
| `OSC "1337;…"` | iterm2 multiplex seeuqnece |
| `OSC "5522;…"` | Clipboard (kitty) |
| `OSC "30001;…"` | Push color onto stack (kitty) |
| `OSC "30101;…"` | Pop color from stack (kitty) |
| `OSC "77119;…"` | Wide chars (mintty) |
[This content has moved to the UAPI group website](https://uapi-group.org/specifications/specs/osc_context/)

View File

@ -13,24 +13,27 @@ SPDX-License-Identifier: LGPL-2.1-or-later
4. Update hwdb (`ninja -C build update-hwdb`, `ninja -C build update-hwdb-autosuspend`, commit separately).
5. Update syscall numbers (`ninja -C build update-syscall-tables update-syscall-header`).
6. [RC1] Update library numbers in `meson.build`
7. Update version number in `meson.version` (e.g. from `256~devel` to `256~rc1` or from `256~rc3` to `256`). Note that this uses a tilde (\~) instead of a hyphen (-) because tildes sort lower in version comparisons according to the [UAPI.10 Version Format Specification](https://uapi-group.org/specifications/specs/version_format_specification/), and we want `255~rc1` to sort lower than `255`.
8. Check dbus docs with `ninja -C build update-dbus-docs`
9. Check manpages list with `ninja -C build update-man-rules`
10. Update translation strings (`ninja -C build systemd-pot`, `ninja -C build systemd-update-po`) - drop the header comments from `systemd.pot` + re-add SPDX before committing. If the only change in a file is the 'POT-Creation-Date' field, then ignore that file.
11. Tag the release: `version="v$(sed 's/~/-/g' meson.version)" && git tag -s "${version}" -m "systemd ${version}"` (tildes are replaced with hyphens, because git doesn't accept the former).
12. Do `ninja -C build`
13. Make sure that the version string and package string match: `build/systemctl --version`
14. [FINAL] Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones)
15. "Draft" a new release on github (https://github.com/systemd/systemd/releases/new), mark "This is a pre-release" if appropriate.
16. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically.
17. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released | Online resources https://systemd.io/`)
18. [FINAL] Create an empty -stable branch: `git push systemd origin/main:refs/heads/v${version}-stable`.
19. [FINAL] Build and upload the documentation (on the -stable branch): `ninja -C build doc-sync`
20. [FINAL] Create a new `ci/v${version}-stable` branch for deb package builds on https://salsa.debian.org/systemd-team/systemd
21. [FINAL] Switch `.semaphore/semaphore-runner.sh` and `mkosi/mkosi.conf.d/debian-ubuntu/mkosi.conf.d/pkgenv.conf` to the new `ci/v${version}-stable` branch on the -stable branch
22. [FINAL] Change the Github Pages branch to the newly created branch (https://github.com/systemd/systemd/settings/pages) and set the 'Custom domain' to 'systemd.io'
23. [FINAL] Update version number in `meson.version` to the devel version of the next release (e.g. from `256` to `257~devel`)
24. [FINAL] Build and upload the documentation (on the main branch): `ninja -C build doc-sync`
8. [RC1] Switch `versionrewrite-pattern` and `versionrewrite-replacement` to RC mode in https://build.opensuse.org/projects/system:systemd/packages/systemd/files/_service?expand=1
9. Update version number in `meson.version` (e.g. from `256~devel` to `256~rc1` or from `256~rc3` to `256`). Note that this uses a tilde (\~) instead of a hyphen (-) because tildes sort lower in version comparisons according to the [UAPI.10 Version Format Specification](https://uapi-group.org/specifications/specs/version_format_specification/), and we want `255~rc1` to sort lower than `255`.
10. Check dbus docs with `ninja -C build update-dbus-docs`
11. Check manpages list with `ninja -C build update-man-rules`
12. Update translation strings (`ninja -C build systemd-pot`, `ninja -C build systemd-update-po`) - drop the header comments from `systemd.pot` + re-add SPDX before committing. If the only change in a file is the 'POT-Creation-Date' field, then ignore that file.
13. Tag the release: `version="v$(sed 's/~/-/g' meson.version)" && git tag -s "${version}" -m "systemd ${version}"` (tildes are replaced with hyphens, because git doesn't accept the former).
14. Do `ninja -C build`
15. Make sure that the version string and package string match: `build/systemctl --version`
16. [FINAL] Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones)
17. "Draft" a new release on github (https://github.com/systemd/systemd/releases/new), mark "This is a pre-release" if appropriate.
18. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically.
19. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released | Online resources https://systemd.io/`)
20. [FINAL] Create an empty -stable branch: `git push systemd origin/main:refs/heads/v${version}-stable`.
21. [FINAL] Build and upload the documentation (on the -stable branch): `ninja -C build doc-sync`
22. [FINAL] Create a new `ci/v${version}-stable` branch for deb package builds on https://salsa.debian.org/systemd-team/systemd
23. [FINAL] Switch `.semaphore/semaphore-runner.sh` and `mkosi/mkosi.pkgenv/mkosi.conf.d/debian-ubuntu.conf`
to the new `ci/v${version}-stable` branch on the -stable branch
24. [FINAL] Switch `versionrewrite-pattern` and `versionrewrite-replacement` to release mode in https://build.opensuse.org/projects/system:systemd/packages/systemd/files/_service?expand=1
25. [FINAL] Change the Github Pages branch to the newly created branch (https://github.com/systemd/systemd/settings/pages) and set the 'Custom domain' to 'systemd.io'
26. [FINAL] Update version number in `meson.version` to the devel version of the next release (e.g. from `256` to `257~devel`)
27. [FINAL] Build and upload the documentation (on the main branch): `ninja -C build doc-sync`
# Steps to a Successful Stable Release

View File

@ -141,6 +141,17 @@
<xi:include href="version-info.xml" xpointer="v250"/></listitem>
</varlistentry>
</variablelist>
<variablelist class='environment-variables'>
<varlistentry>
<term><varname>$SYSTEMD_NSS_RESOLVE_INTERFACE</varname></term>
<listitem><para>Takes an interface name or index as an argument. When specified, answers will only be
obtained from name servers belonging to the specified interface.</para>
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>

View File

@ -109,13 +109,15 @@
<varlistentry>
<term><option>--list</option></term>
<listitem><para>Lists all active inhibition locks instead of
acquiring one.</para></listitem>
<listitem><para>Lists all active inhibition locks instead of acquiring one. It can be filtered using
<option>--what=</option>, <option>--who=</option>, <option>--why=</option>, or
<option>--mode=</option>.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="no-ask-password" />
<xi:include href="standard-options.xml" xpointer="no-pager" />
<xi:include href="standard-options.xml" xpointer="no-legend" />
<xi:include href="standard-options.xml" xpointer="json" />
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>

View File

@ -90,6 +90,10 @@
<entry><constant>ww</constant></entry>
<entry>Wireless wide area network (WWAN)</entry>
</row>
<row>
<entry><constant>mc</constant></entry>
<entry>Management Component Transport Protocol (MCTP)</entry>
</row>
</tbody>
</tgroup>
</table>
@ -561,6 +565,16 @@
<xi:include href="version-info.xml" xpointer="v259"/>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>v260</constant></term>
<listitem><para>MCTP interfaces are now assigned persistent names, using a <constant>mc</constant>
prefix.</para>
<xi:include href="version-info.xml" xpointer="v260"/>
</listitem>
</varlistentry>
</variablelist>
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this

View File

@ -354,6 +354,7 @@
</listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="no-ask-password" />
<xi:include href="standard-options.xml" xpointer="no-pager" />
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />

View File

@ -9,5 +9,5 @@ Environment=
GIT_URL=https://salsa.debian.org/systemd-team/systemd.git
GIT_SUBDIR=debian
GIT_BRANCH=debian/master
GIT_COMMIT=efdd7a6377c7251011ca2c1a59115d482d25fe61
GIT_COMMIT=6f15bdaae7014c233b662ac4a33d464893b81b36
PKG_SUBDIR=debian

View File

@ -10,6 +10,10 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
# This implements the UAPI.15 "OSC 3008: Hierarchical Context Signalling"
# specification for the shell prompt. For details see:
# https://uapi-group.org/specifications/specs/osc_context/
# Not bash?
[ -n "${BASH_VERSION:-}" ] || return 0

View File

@ -42,7 +42,7 @@ _varlinkctl() {
local i n verb comps
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
local -A OPTS=(
[STANDALONE]='-h --help --version --no-pager -q --quiet
[STANDALONE]='-h --help --version --no-pager -q --quiet --no-ask-password
--oneway --collect --more --exec -j -E'
[ARG]='--graceful --timeout --push-fd --json'
)

View File

@ -3914,7 +3914,7 @@ int bus_exec_context_set_transient_property(
if (r < 0)
return r;
if (empty) {
if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
c->bind_mounts = NULL;
c->n_bind_mounts = 0;
@ -3959,7 +3959,7 @@ int bus_exec_context_set_transient_property(
if (r < 0)
return r;
if (empty) {
if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
c->temporary_filesystems = NULL;
c->n_temporary_filesystems = 0;

View File

@ -348,7 +348,7 @@ static void service_start_watchdog(Service *s) {
log_unit_warning_errno(UNIT(s), r, "Failed to install watchdog timer: %m");
}
usec_t service_restart_usec_next(Service *s) {
usec_t service_restart_usec_next(const Service *s) {
unsigned n_restarts_next;
assert(s);

View File

@ -266,7 +266,7 @@ extern const UnitVTable service_vtable;
int service_set_socket_fd(Service *s, int fd, struct Socket *socket, struct SocketPeer *peer, bool selinux_context_net);
void service_release_socket_fd(Service *s);
usec_t service_restart_usec_next(Service *s);
usec_t service_restart_usec_next(const Service *s) _pure_;
int service_determine_exec_selinux_label(Service *s, char **ret);

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <fcntl.h>
#include <fnmatch.h>
#include <getopt.h>
#include <stdio.h>
#include <unistd.h>
@ -18,6 +19,7 @@
#include "log.h"
#include "main-func.h"
#include "pager.h"
#include "parse-argument.h"
#include "polkit-agent.h"
#include "pretty-print.h"
#include "process-util.h"
@ -28,13 +30,14 @@
#include "terminal-util.h"
#include "user-util.h"
static const char *arg_what = "idle:sleep:shutdown";
static const char *arg_what = NULL;
static const char *arg_who = NULL;
static const char *arg_why = "Unknown reason";
static const char *arg_why = NULL;
static const char *arg_mode = NULL;
static bool arg_ask_password = true;
static PagerFlags arg_pager_flags = 0;
static bool arg_legend = true;
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
static enum {
ACTION_INHIBIT,
@ -63,6 +66,8 @@ static int print_inhibitors(sd_bus *bus) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(table_unrefp) Table *table = NULL;
_cleanup_strv_free_ char **what_filter = NULL;
int r;
pager_open(arg_pager_flags);
@ -83,6 +88,12 @@ static int print_inhibitors(sd_bus *bus) {
if (r < 0)
return bus_log_parse_error(r);
if (arg_what) {
what_filter = strv_split(arg_what, ":");
if (!what_filter)
return log_oom();
}
for (;;) {
_cleanup_free_ char *comm = NULL, *u = NULL;
const char *what, *who, *why, *mode;
@ -94,6 +105,25 @@ static int print_inhibitors(sd_bus *bus) {
if (r == 0)
break;
if (what_filter) {
bool skip = false;
STRV_FOREACH(op, what_filter)
if (!string_contains_word(what, ":", *op)) {
skip = true;
break;
}
if (skip)
continue;
}
if (arg_who && !streq(who, arg_who))
continue;
if (arg_why && fnmatch(arg_why, why, FNM_CASEFOLD) != 0)
continue;
if (arg_mode && !streq(mode, arg_mode))
continue;
@ -124,12 +154,12 @@ static int print_inhibitors(sd_bus *bus) {
table_set_header(table, arg_legend);
r = table_print(table, NULL);
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
if (r < 0)
return table_log_print_error(r);
return r;
}
if (arg_legend) {
if (arg_legend && !sd_json_format_enabled(arg_json_format_flags)) {
if (table_isempty(table))
printf("No inhibitors.\n");
else
@ -154,6 +184,8 @@ static int help(void) {
" --no-ask-password Do not attempt interactive authorization\n"
" --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n"
" --json=pretty|short|off\n"
" Generate JSON output\n"
" --what=WHAT Operations to inhibit, colon separated list of:\n"
" shutdown, sleep, idle, handle-power-key,\n"
" handle-suspend-key, handle-hibernate-key,\n"
@ -183,6 +215,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NO_ASK_PASSWORD,
ARG_NO_PAGER,
ARG_NO_LEGEND,
ARG_JSON,
};
static const struct option options[] = {
@ -196,10 +229,11 @@ static int parse_argv(int argc, char *argv[]) {
{ "list", no_argument, NULL, ARG_LIST },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "json", required_argument, NULL, ARG_JSON },
{}
};
int c;
int c, r;
assert(argc >= 0);
assert(argv);
@ -249,6 +283,13 @@ static int parse_argv(int argc, char *argv[]) {
arg_legend = false;
break;
case ARG_JSON:
r = parse_json_argument(optarg, &arg_json_format_flags);
if (r <= 0)
return r;
break;
case '?':
return -EINVAL;
@ -294,6 +335,9 @@ static int run(int argc, char *argv[]) {
/* Ignore SIGINT and allow the forked process to receive it */
(void) ignore_signals(SIGINT);
if (!arg_what)
arg_what = "idle:sleep:shutdown";
if (!arg_who) {
w = strv_join(argv + optind, " ");
if (!w)
@ -302,6 +346,9 @@ static int run(int argc, char *argv[]) {
arg_who = w;
}
if (!arg_why)
arg_why = "Unknown reason";
if (!arg_mode)
arg_mode = "block";

View File

@ -12,6 +12,7 @@
#include "glyph-util.h"
#include "in-addr-util.h"
#include "json-util.h"
#include "netlink-util.h"
#include "nss-util.h"
#include "resolved-def.h"
#include "signal-util.h"
@ -188,6 +189,23 @@ static uint64_t query_flags(void) {
query_flag("SYSTEMD_NSS_RESOLVE_NETWORK", 0, SD_RESOLVED_NO_NETWORK);
}
static int query_ifindex(void) {
int ifindex;
const char *e;
e = secure_getenv("SYSTEMD_NSS_RESOLVE_INTERFACE");
if (!e)
return 0;
ifindex = rtnl_resolve_interface(/* rtnl= */ NULL, e);
if (ifindex < 0) {
log_debug_errno(ifindex, "Failed to resolve $SYSTEMD_NSS_RESOLVE_INTERFACE, ignoring: %m");
ifindex = 0;
}
return ifindex;
}
enum nss_status _nss_resolve_gethostbyname4_r(
const char *name,
struct gaih_addrtuple **pat,
@ -217,7 +235,8 @@ enum nss_status _nss_resolve_gethostbyname4_r(
r = sd_json_buildo(
&cparams,
SD_JSON_BUILD_PAIR_STRING("name", name),
SD_JSON_BUILD_PAIR_UNSIGNED("flags", query_flags()));
SD_JSON_BUILD_PAIR_UNSIGNED("flags", query_flags()),
SD_JSON_BUILD_PAIR_UNSIGNED("ifindex", query_ifindex()));
if (r < 0)
goto fail;
@ -386,7 +405,8 @@ enum nss_status _nss_resolve_gethostbyname3_r(
&cparams,
SD_JSON_BUILD_PAIR_STRING("name", name),
SD_JSON_BUILD_PAIR_INTEGER("family", af),
SD_JSON_BUILD_PAIR_UNSIGNED("flags", query_flags()));
SD_JSON_BUILD_PAIR_UNSIGNED("flags", query_flags()),
SD_JSON_BUILD_PAIR_UNSIGNED("ifindex", query_ifindex()));
if (r < 0)
goto fail;
@ -606,7 +626,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
&cparams,
SD_JSON_BUILD_PAIR_BYTE_ARRAY("address", addr, len),
SD_JSON_BUILD_PAIR_INTEGER("family", af),
SD_JSON_BUILD_PAIR_UNSIGNED("flags", query_flags()));
SD_JSON_BUILD_PAIR_UNSIGNED("flags", query_flags()),
SD_JSON_BUILD_PAIR_UNSIGNED("ifindex", query_ifindex()));
if (r < 0)
goto fail;

View File

@ -158,13 +158,14 @@ static int verify_features(
bool *ret_has_rk,
bool *ret_has_client_pin,
bool *ret_has_up,
bool *ret_has_uv) {
bool *ret_has_uv,
bool *ret_has_always_uv) {
_cleanup_(fido_cbor_info_free_wrapper) fido_cbor_info_t *di = NULL;
bool found_extension = false;
char **e, **o;
const bool *b;
bool has_rk = false, has_client_pin = false, has_up = true, has_uv = false; /* Defaults are per table in 5.4 in FIDO2 spec */
bool has_rk = false, has_client_pin = false, has_up = true, has_uv = false, has_always_uv = false; /* Defaults are per table in 5.4 in FIDO2 spec */
size_t n;
int r;
@ -205,6 +206,8 @@ static int verify_features(
has_up = b[i];
if (streq(o[i], "uv"))
has_uv = b[i];
if (streq(o[i], "alwaysUv"))
has_always_uv = b[i];
}
if (!found_extension)
@ -215,11 +218,13 @@ static int verify_features(
log_debug("Has rk ('Resident Key') support: %s\n"
"Has clientPin support: %s\n"
"Has up ('User Presence') support: %s\n"
"Has uv ('User Verification') support: %s\n",
"Has uv ('User Verification') support: %s\n"
"Has alwaysUv ('User Verification' required): %s\n",
yes_no(has_rk),
yes_no(has_client_pin),
yes_no(has_up),
yes_no(has_uv));
yes_no(has_uv),
yes_no(has_always_uv));
if (ret_has_rk)
*ret_has_rk = has_rk;
@ -229,6 +234,8 @@ static int verify_features(
*ret_has_up = has_up;
if (ret_has_uv)
*ret_has_uv = has_uv;
if (ret_has_always_uv)
*ret_has_always_uv = has_always_uv;
return 0;
}
@ -320,7 +327,7 @@ static int fido2_is_cred_in_specific_token(
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Failed to open FIDO2 device %s: %s", path, sym_fido_strerr(r));
r = verify_features(d, path, LOG_ERR, NULL, NULL, &has_up, &has_uv);
r = verify_features(d, path, LOG_ERR, /* ret_has_rk= */ NULL, /* ret_has_client_pin= */ NULL, &has_up, &has_uv, /* ret_has_always_uv= */ NULL);
if (r == -ENODEV) { /* Not a FIDO2 device or lacking HMAC-SECRET extension */
log_debug_errno(r, "%s is not a FIDO2 device, or it lacks the hmac-secret extension", path);
return false;
@ -432,7 +439,7 @@ static int fido2_use_hmac_hash_specific_token(
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Failed to open FIDO2 device %s: %s", path, sym_fido_strerr(r));
r = verify_features(d, path, LOG_ERR, NULL, &has_client_pin, &has_up, &has_uv);
r = verify_features(d, path, LOG_ERR, /* ret_has_rk= */ NULL, &has_client_pin, &has_up, &has_uv, /* ret_has_always_uv= */ NULL);
if (r < 0)
return r;
@ -745,7 +752,7 @@ int fido2_generate_hmac_hash(
_cleanup_(fido_cred_free_wrapper) fido_cred_t *c = NULL;
_cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL;
_cleanup_(erase_and_freep) char *used_pin = NULL;
bool has_rk, has_client_pin, has_up, has_uv;
bool has_rk, has_client_pin, has_up, has_uv, has_always_uv;
_cleanup_free_ char *cid_copy = NULL;
size_t cid_size, secret_size;
const void *cid, *secret;
@ -787,7 +794,7 @@ int fido2_generate_hmac_hash(
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Failed to open FIDO2 device %s: %s", device, sym_fido_strerr(r));
r = verify_features(d, device, LOG_ERR, &has_rk, &has_client_pin, &has_up, &has_uv);
r = verify_features(d, device, LOG_ERR, &has_rk, &has_client_pin, &has_up, &has_uv, &has_always_uv);
if (r < 0)
return r;
@ -807,6 +814,19 @@ int fido2_generate_hmac_hash(
lock_with &= ~FIDO2ENROLL_UV;
}
if (has_always_uv && !(FLAGS_SET(lock_with, FIDO2ENROLL_PIN) || FLAGS_SET(lock_with, FIDO2ENROLL_UV))) {
if (has_uv) {
log_notice("FIDO2 device %s enforces 'always user verification', forcing user verification.", device);
lock_with |= FIDO2ENROLL_UV;
} else if (has_client_pin) {
log_notice("FIDO2 device %s enforces 'always user verification', but doesn't support user verification, forcing PIN.", device);
lock_with |= FIDO2ENROLL_PIN;
} else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"FIDO2 device %s enforces 'always user verification', but doesn't support user verification or PIN, cannot proceed.",
device);
}
c = sym_fido_cred_new();
if (!c)
return log_oom();
@ -1124,7 +1144,8 @@ static int check_device_is_fido2_with_hmac_secret(
bool *ret_has_rk,
bool *ret_has_client_pin,
bool *ret_has_up,
bool *ret_has_uv) {
bool *ret_has_uv,
bool *ret_has_always_uv) {
_cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL;
int r;
@ -1138,9 +1159,9 @@ static int check_device_is_fido2_with_hmac_secret(
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Failed to open FIDO2 device %s: %s", path, sym_fido_strerr(r));
r = verify_features(d, path, LOG_DEBUG, ret_has_rk, ret_has_client_pin, ret_has_up, ret_has_uv);
r = verify_features(d, path, LOG_DEBUG, ret_has_rk, ret_has_client_pin, ret_has_up, ret_has_uv, ret_has_always_uv);
if (r == -ENODEV) { /* Not a FIDO2 device, or not implementing 'hmac-secret' */
*ret_has_rk = *ret_has_client_pin = *ret_has_up = *ret_has_uv = false;
*ret_has_rk = *ret_has_client_pin = *ret_has_up = *ret_has_uv = *ret_has_always_uv = false;
return false;
}
if (r < 0)
@ -1178,7 +1199,7 @@ int fido2_list_devices(void) {
goto finish;
}
t = table_new("path", "manufacturer", "product", "compatible", "rk", "clientpin", "up", "uv");
t = table_new("path", "manufacturer", "product", "compatible", "rk", "clientpin", "up", "uv", "alwaysuv");
if (!t) {
r = log_oom();
goto finish;
@ -1186,7 +1207,7 @@ int fido2_list_devices(void) {
for (size_t i = 0; i < found; i++) {
const fido_dev_info_t *entry;
bool has_rk, has_client_pin, has_up, has_uv;
bool has_rk, has_client_pin, has_up, has_uv, has_always_uv;
entry = sym_fido_dev_info_ptr(di, i);
if (!entry) {
@ -1195,7 +1216,7 @@ int fido2_list_devices(void) {
goto finish;
}
r = check_device_is_fido2_with_hmac_secret(sym_fido_dev_info_path(entry), &has_rk, &has_client_pin, &has_up, &has_uv);
r = check_device_is_fido2_with_hmac_secret(sym_fido_dev_info_path(entry), &has_rk, &has_client_pin, &has_up, &has_uv, &has_always_uv);
if (r < 0)
goto finish;
bool compatible = r > 0;
@ -1209,7 +1230,8 @@ int fido2_list_devices(void) {
TABLE_BOOLEAN_CHECKMARK, has_rk,
TABLE_BOOLEAN_CHECKMARK, has_client_pin,
TABLE_BOOLEAN_CHECKMARK, has_up,
TABLE_BOOLEAN_CHECKMARK, has_uv);
TABLE_BOOLEAN_CHECKMARK, has_uv,
TABLE_BOOLEAN_CHECKMARK, has_always_uv);
if (r < 0) {
table_log_add_error(r);
goto finish;
@ -1227,7 +1249,8 @@ int fido2_list_devices(void) {
"%1$sLegend: RK %2$s Resident key%3$s\n"
"%1$s CLIENTPIN %2$s PIN request%3$s\n"
"%1$s UP %2$s User presence%3$s\n"
"%1$s UV %2$s User verification%3$s\n",
"%1$s UV %2$s User verification%3$s\n"
"%1$s AlwaysUV %2$s User verification Required%3$s\n",
ansi_grey(),
glyph(GLYPH_ARROW_RIGHT),
ansi_normal());
@ -1287,7 +1310,8 @@ int fido2_find_device_auto(char **ret) {
/* ret_has_rk= */ NULL,
/* ret_has_client_pin= */ NULL,
/* ret_has_up= */ NULL,
/* ret_has_uv= */ NULL);
/* ret_has_uv= */ NULL,
/* ret_has_always_uv= */ NULL);
if (r < 0)
goto finish;
if (!r) {

View File

@ -30,6 +30,7 @@ static const NamingScheme naming_schemes[] = {
{ "v257", NAMING_V257 },
{ "v258", NAMING_V258 },
{ "v259", NAMING_V259 },
{ "v260", NAMING_V260 },
/* … add more schemes here, as the logic to name devices is updated … */
EXTRA_NET_NAMING_MAP

View File

@ -43,6 +43,7 @@ typedef enum NamingSchemeFlags {
NAMING_DEVICETREE_PORT_ALIASES = 1 << 19, /* Include aliases of OF nodes of a netdev itself, not just its parent. See PR #33958. */
NAMING_USE_INTERFACE_PROPERTY = 1 << 20, /* Use INTERFACE udev property, rather than sysname, when no renaming is requested. */
NAMING_DEVICETREE_ALIASES_WLAN = 1 << 21, /* Generate names from devicetree aliases for WLAN devices */
NAMING_MCTP = 1 << 22, /* Use "mc" prefix for MCTP devices */
/* And now the masks that combine the features above */
NAMING_V238 = 0,
@ -65,6 +66,7 @@ typedef enum NamingSchemeFlags {
NAMING_V257 = NAMING_V255 | NAMING_FIRMWARE_NODE_SUN | NAMING_DEVICETREE_PORT_ALIASES,
NAMING_V258 = NAMING_V257 | NAMING_USE_INTERFACE_PROPERTY,
NAMING_V259 = NAMING_V258 | NAMING_DEVICETREE_ALIASES_WLAN,
NAMING_V260 = NAMING_V259 | NAMING_MCTP,
EXTRA_NET_NAMING_SCHEMES

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "bus-polkit.h"
#include "varlink-io.systemd.sysext.h"
static SD_VARLINK_DEFINE_ENUM_TYPE(
@ -19,24 +20,28 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_DEFINE_INPUT_BY_TYPE(class, ImageClass, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(force, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(noReload, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(noexec, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_INPUT(noexec, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_METHOD(
Unmerge,
SD_VARLINK_DEFINE_INPUT_BY_TYPE(class, ImageClass, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(noReload, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_INPUT(noReload, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_METHOD(
Refresh,
SD_VARLINK_DEFINE_INPUT_BY_TYPE(class, ImageClass, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(force, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(noReload, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(noexec, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_INPUT(noexec, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_METHOD_FULL(
List,
SD_VARLINK_REQUIRES_MORE,
SD_VARLINK_DEFINE_INPUT_BY_TYPE(class, ImageClass, SD_VARLINK_NULLABLE),
VARLINK_DEFINE_POLKIT_INPUT,
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(Class, ImageClass, 0),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(Type, ImageType, 0),
SD_VARLINK_DEFINE_OUTPUT(Name, SD_VARLINK_STRING, 0),

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
"https://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
<!--
SPDX-License-Identifier: LGPL-2.1-or-later
This file is part of systemd.
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
-->
<policyconfig>
<vendor>The systemd Project</vendor>
<vendor_url>https://systemd.io</vendor_url>
<action id="io.systemd.sysext.manage">
<description gettext-domain="systemd">Allow managing (merging, unmerging, ...) of system extension images.</description>
<message gettext-domain="systemd">Authentication is required for an application to manage a system extension image.</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
</action>
<action id="io.systemd.sysext.read">
<description gettext-domain="systemd">Allow reading (listing, ...) of system extension images.</description>
<message gettext-domain="systemd">Authentication is required for an application to list system extension images.</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
<action id="io.systemd.confext.manage">
<description gettext-domain="systemd">Allow managing (merging, unmerging, ...) of configuration extension images.</description>
<message gettext-domain="systemd">Authentication is required for an application to manage a configuration extension image.</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
</action>
<action id="io.systemd.confext.read">
<description gettext-domain="systemd">Allow reading (listing, ...) of configuration extension images.</description>
<message gettext-domain="systemd">Authentication is required for an application to list configuration extension images.</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
</policyconfig>

View File

@ -18,4 +18,7 @@ if conf.get('ENABLE_SYSEXT') == 1
install_symlink('systemd-confext',
pointing_to : 'systemd-sysext',
install_dir : bindir)
install_data('io.systemd.sysext.policy',
install_dir : polkitpolicydir)
endif

View File

@ -14,6 +14,7 @@
#include "blkid-util.h"
#include "blockdev-util.h"
#include "build.h"
#include "bus-polkit.h"
#include "bus-unit-util.h"
#include "bus-util.h"
#include "capability-util.h"
@ -117,6 +118,8 @@ static const struct {
const char *full_identifier;
const char *short_identifier;
const char *short_identifier_plural;
const char *polkit_rw_action_id;
const char *polkit_ro_action_id;
const char *blurb;
const char *dot_directory_name;
const char *directory_name;
@ -132,6 +135,8 @@ static const struct {
.full_identifier = "systemd-sysext",
.short_identifier = "sysext",
.short_identifier_plural = "extensions",
.polkit_rw_action_id = "io.systemd.sysext.manage",
.polkit_ro_action_id = "io.systemd.sysext.read",
.blurb = "Merge system extension images into /usr/ and /opt/.",
.dot_directory_name = ".systemd-sysext",
.level_env = "SYSEXT_LEVEL",
@ -146,6 +151,8 @@ static const struct {
.full_identifier = "systemd-confext",
.short_identifier = "confext",
.short_identifier_plural = "confexts",
.polkit_rw_action_id = "io.systemd.confext.manage",
.polkit_ro_action_id = "io.systemd.confext.read",
.blurb = "Merge configuration extension images into /etc/.",
.dot_directory_name = ".systemd-confext",
.level_env = "CONFEXT_LEVEL",
@ -623,13 +630,16 @@ static int vl_method_unmerge(sd_varlink *link, sd_json_variant *parameters, sd_v
static const sd_json_dispatch_field dispatch_table[] = {
{ "class", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MethodUnmergeParameters, class), 0 },
{ "noReload", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(MethodUnmergeParameters, no_reload), 0 },
VARLINK_DISPATCH_POLKIT_FIELD,
{}
};
MethodUnmergeParameters p = {
.no_reload = -1,
};
Hashmap **polkit_registry = ASSERT_PTR(userdata);
_cleanup_strv_free_ char **hierarchies = NULL;
ImageClass image_class = arg_image_class;
bool no_reload;
int r;
assert(link);
@ -638,13 +648,24 @@ static int vl_method_unmerge(sd_varlink *link, sd_json_variant *parameters, sd_v
if (r != 0)
return r;
no_reload = p.no_reload >= 0 ? p.no_reload : arg_no_reload;
r = parse_image_class_parameter(link, p.class, &image_class, &hierarchies);
if (r < 0)
return r;
r = unmerge(image_class,
hierarchies ?: arg_hierarchies,
p.no_reload >= 0 ? p.no_reload : arg_no_reload);
r = varlink_verify_polkit_async(
link,
/* bus= */ NULL,
image_class_info[image_class].polkit_rw_action_id,
(const char**) STRV_MAKE(
"verb", "unmerge",
"noReload", one_zero(no_reload)),
polkit_registry);
if (r <= 0)
return r;
r = unmerge(image_class, hierarchies ?: arg_hierarchies, no_reload);
if (r < 0)
return r;
@ -2261,6 +2282,7 @@ static int parse_merge_parameters(sd_varlink *link, sd_json_variant *parameters,
{ "force", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MethodMergeParameters, force), 0 },
{ "noReload", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MethodMergeParameters, no_reload), 0 },
{ "noexec", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MethodMergeParameters, noexec), 0 },
VARLINK_DISPATCH_POLKIT_FIELD,
{}
};
@ -2272,6 +2294,7 @@ static int parse_merge_parameters(sd_varlink *link, sd_json_variant *parameters,
}
static int vl_method_merge(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
Hashmap **polkit_registry = ASSERT_PTR(userdata);
_cleanup_hashmap_free_ Hashmap *images = NULL;
MethodMergeParameters p = {
.force = -1,
@ -2280,7 +2303,8 @@ static int vl_method_merge(sd_varlink *link, sd_json_variant *parameters, sd_var
};
_cleanup_strv_free_ char **hierarchies = NULL;
ImageClass image_class = arg_image_class;
int r;
bool force, no_reload;
int r, noexec;
assert(link);
@ -2292,6 +2316,23 @@ static int vl_method_merge(sd_varlink *link, sd_json_variant *parameters, sd_var
if (r < 0)
return r;
force = p.force >= 0 ? p.force : arg_force;
no_reload = p.no_reload >= 0 ? p.no_reload : arg_no_reload;
noexec = p.noexec >= 0 ? p.noexec : arg_noexec;
r = varlink_verify_polkit_async(
link,
/* bus= */ NULL,
image_class_info[image_class].polkit_rw_action_id,
(const char**) STRV_MAKE(
"verb", "merge",
"force", one_zero(force),
"noReload", one_zero(no_reload),
"noexec", one_zero(noexec > 0)),
polkit_registry);
if (r <= 0)
return r;
r = image_discover_and_read_metadata(image_class, &images);
if (r < 0)
return r;
@ -2306,12 +2347,7 @@ static int vl_method_merge(sd_varlink *link, sd_json_variant *parameters, sd_var
if (r > 0)
return sd_varlink_errorbo(link, "io.systemd.sysext.AlreadyMerged", SD_JSON_BUILD_PAIR_STRING("hierarchy", which));
r = merge(image_class,
hierarchies ?: arg_hierarchies,
p.force >= 0 ? p.force : arg_force,
p.no_reload >= 0 ? p.no_reload : arg_no_reload,
p.noexec >= 0 ? p.noexec : arg_noexec,
images);
r = merge(image_class, hierarchies ?: arg_hierarchies, force, no_reload, noexec, images);
if (r < 0)
return r;
@ -2381,9 +2417,11 @@ static int vl_method_refresh(sd_varlink *link, sd_json_variant *parameters, sd_v
.no_reload = -1,
.noexec = -1,
};
Hashmap **polkit_registry = ASSERT_PTR(userdata);
_cleanup_strv_free_ char **hierarchies = NULL;
ImageClass image_class = arg_image_class;
int r;
bool force, no_reload;
int r, noexec;
assert(link);
@ -2395,11 +2433,24 @@ static int vl_method_refresh(sd_varlink *link, sd_json_variant *parameters, sd_v
if (r < 0)
return r;
r = refresh(image_class,
hierarchies ?: arg_hierarchies,
p.force >= 0 ? p.force : arg_force,
p.no_reload >= 0 ? p.no_reload : arg_no_reload,
p.noexec >= 0 ? p.noexec : arg_noexec);
force = p.force >= 0 ? p.force : arg_force;
no_reload = p.no_reload >= 0 ? p.no_reload : arg_no_reload;
noexec = p.noexec >= 0 ? p.noexec : arg_noexec;
r = varlink_verify_polkit_async(
link,
/* bus= */ NULL,
image_class_info[image_class].polkit_rw_action_id,
(const char**) STRV_MAKE(
"verb", "refresh",
"force", one_zero(force),
"noReload", one_zero(no_reload),
"noexec", one_zero(noexec > 0)),
polkit_registry);
if (r <= 0)
return r;
r = refresh(image_class, hierarchies ?: arg_hierarchies, force, no_reload, noexec);
if (r < 0)
return r;
@ -2445,9 +2496,11 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
static const sd_json_dispatch_field dispatch_table[] = {
{ "class", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, 0 },
VARLINK_DISPATCH_POLKIT_FIELD,
{}
};
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
Hashmap **polkit_registry = ASSERT_PTR(userdata);
int r;
assert(link);
@ -2462,6 +2515,15 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
if (r < 0)
return r;
r = varlink_verify_polkit_async(
link,
/* bus= */ NULL,
image_class_info[image_class].polkit_ro_action_id,
(const char**) STRV_MAKE("verb", "list"),
polkit_registry);
if (r <= 0)
return r;
_cleanup_hashmap_free_ Hashmap *images = NULL;
r = image_discover(RUNTIME_SCOPE_SYSTEM, image_class, arg_root, &images);
if (r < 0)
@ -2727,10 +2789,14 @@ static int run(int argc, char *argv[]) {
if (arg_varlink) {
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL;
_cleanup_hashmap_free_ Hashmap *polkit_registry = NULL;
/* Invocation as Varlink service */
r = varlink_server_new(&varlink_server, SD_VARLINK_SERVER_ROOT_ONLY, NULL);
r = varlink_server_new(
&varlink_server,
SD_VARLINK_SERVER_ACCOUNT_UID|SD_VARLINK_SERVER_INHERIT_USERDATA,
&polkit_registry);
if (r < 0)
return log_error_errno(r, "Failed to allocate Varlink server: %m");

View File

@ -1307,7 +1307,7 @@ static int get_ifname_prefix(sd_device *dev, const char **ret) {
if (r < 0)
return r;
/* handle only ARPHRD_ETHER, ARPHRD_SLIP and ARPHRD_INFINIBAND devices */
/* handle only ARPHRD_ETHER, ARPHRD_SLIP, ARPHRD_INFINIBAND, and ARPHDR_MCTP devices */
switch (iftype) {
case ARPHRD_ETHER: {
if (device_is_devtype(dev, "wlan") > 0)
@ -1329,6 +1329,13 @@ static int get_ifname_prefix(sd_device *dev, const char **ret) {
*ret = "sl";
return 0;
case ARPHRD_MCTP:
if (!naming_scheme_has(NAMING_MCTP))
return -EOPNOTSUPP;
*ret = "mc";
return 0;
default:
return -EOPNOTSUPP;
}

View File

@ -9,6 +9,7 @@
#include "sd-varlink.h"
#include "build.h"
#include "bus-util.h"
#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
@ -21,6 +22,7 @@
#include "parse-argument.h"
#include "parse-util.h"
#include "pidfd-util.h"
#include "polkit-agent.h"
#include "pretty-print.h"
#include "process-util.h"
#include "string-util.h"
@ -46,6 +48,7 @@ static char **arg_graceful = NULL;
static usec_t arg_timeout = 0;
static bool arg_exec = false;
static PushFds arg_push_fds = {};
static bool arg_ask_password = true;
static void push_fds_done(PushFds *p) {
assert(p);
@ -87,6 +90,7 @@ static int help(void) {
"\n%3$sOptions:%4$s\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --no-ask-password Do not prompt for password\n"
" --no-pager Do not pipe output into a pager\n"
" --more Request multiple responses\n"
" --collect Collect multiple responses in a JSON array\n"
@ -126,6 +130,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_TIMEOUT,
ARG_EXEC,
ARG_PUSH_FD,
ARG_NO_ASK_PASSWORD,
};
static const struct option options[] = {
@ -141,6 +146,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
{ "exec", no_argument, NULL, ARG_EXEC },
{ "push-fd", required_argument, NULL, ARG_PUSH_FD },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{},
};
@ -253,6 +259,10 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
case ARG_NO_ASK_PASSWORD:
arg_ask_password = false;
break;
case '?':
return -EINVAL;
@ -619,6 +629,8 @@ static int verb_call(int argc, char *argv[], void *userdata) {
if (arg_exec && (arg_collect || (arg_method_flags & (SD_VARLINK_METHOD_ONEWAY|SD_VARLINK_METHOD_MORE))) != 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--exec and --collect/--more/--oneway may not be combined.");
(void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
url = argv[1];
method = argv[2];
parameter = argc > 3 && !streq(argv[3], "-") ? argv[3] : NULL;

View File

@ -811,6 +811,33 @@ grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file
varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Unmerge '{}'
(! grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file )
# And again, but unprivileged, if we have pidfds and polkit support
# Also check that the required policy is installed, as packages might be out of date with the test
if systemd-analyze compare-versions "$(uname -r)" ge 6.5 && \
systemd-analyze compare-versions "$(pkcheck --version | awk '{print $3}')" ge 124 && \
test -f /usr/share/polkit-1/actions/io.systemd.sysext.policy; then
mkdir -p /etc/polkit-1/rules.d
cat >/etc/polkit-1/rules.d/sysext-unpriv.rules <<'EOF'
polkit.addRule(function(action, subject) {
if (action.id == "io.systemd.sysext.manage" &&
subject.user == "testuser") {
return polkit.Result.YES;
}
});
EOF
systemctl try-reload-or-restart polkit.service
run0 -u testuser varlinkctl call --more /run/systemd/io.systemd.sysext io.systemd.sysext.List '{}'
(! grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file )
run0 -u testuser varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Merge '{"allowInteractiveAuthentication": true}'
grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file
run0 -u testuser varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Refresh '{"allowInteractiveAuthentication": true}'
grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file
run0 -u testuser varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Unmerge '{"allowInteractiveAuthentication": true}'
(! grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file )
rm -f /etc/polkit-1/rules.d/sysext-unpriv.rules
systemctl try-reload-or-restart polkit.service
fi
# Check that extensions cannot contain os-release
mkdir -p /run/extensions/app-reject/usr/lib/{extension-release.d/,systemd/system}
echo "ID=_any" >/run/extensions/app-reject/usr/lib/extension-release.d/extension-release.app-reject

View File

@ -26,6 +26,8 @@ at_exit() {
rm -rf "$IMAGE_DIR"
rm -f /etc/polkit-1/rules.d/sysext-unpriv.rules
loginctl disable-linger testuser
}

View File

@ -18,7 +18,7 @@ ConditionCapability=CAP_SYS_ADMIN
[Socket]
ListenStream=/run/systemd/io.systemd.sysext
FileDescriptorName=varlink
SocketMode=0600
SocketMode=0666
Accept=yes
MaxConnectionsPerSource=16