mirror of
https://github.com/systemd/systemd
synced 2026-03-25 08:14:54 +01:00
Compare commits
18 Commits
90f4c0473a
...
9e418cd075
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e418cd075 | ||
|
|
9a34971421 | ||
|
|
cc1ed77280 | ||
|
|
f603bc37f4 | ||
|
|
18d90c1628 | ||
|
|
d91aed3b55 | ||
|
|
f33d550d44 | ||
|
|
27aba70b3b | ||
|
|
198898c07b | ||
|
|
cb6ccb1c31 | ||
|
|
ea73b8887b | ||
|
|
b1192a01cd | ||
|
|
16bae207c2 | ||
|
|
8619c65fcf | ||
|
|
2824182a12 | ||
|
|
c40ab2337f | ||
|
|
34f41471fc | ||
|
|
a2d53619c0 |
@ -1,339 +1 @@
|
|||||||
---
|
[This content has moved to the UAPI group website](https://uapi-group.org/specifications/specs/osc_context/)
|
||||||
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) |
|
|
||||||
|
|||||||
@ -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).
|
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`).
|
5. Update syscall numbers (`ninja -C build update-syscall-tables update-syscall-header`).
|
||||||
6. [RC1] Update library numbers in `meson.build`
|
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. [RC1] Switch `versionrewrite-pattern` and `versionrewrite-replacement` to RC mode in https://build.opensuse.org/projects/system:systemd/packages/systemd/files/_service?expand=1
|
||||||
8. Check dbus docs with `ninja -C build update-dbus-docs`
|
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`.
|
||||||
9. Check manpages list with `ninja -C build update-man-rules`
|
10. Check dbus docs with `ninja -C build update-dbus-docs`
|
||||||
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. Check manpages list with `ninja -C build update-man-rules`
|
||||||
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. 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.
|
||||||
12. Do `ninja -C build`
|
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).
|
||||||
13. Make sure that the version string and package string match: `build/systemctl --version`
|
14. Do `ninja -C build`
|
||||||
14. [FINAL] Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones)
|
15. Make sure that the version string and package string match: `build/systemctl --version`
|
||||||
15. "Draft" a new release on github (https://github.com/systemd/systemd/releases/new), mark "This is a pre-release" if appropriate.
|
16. [FINAL] Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones)
|
||||||
16. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically.
|
17. "Draft" a new release on github (https://github.com/systemd/systemd/releases/new), mark "This is a pre-release" if appropriate.
|
||||||
17. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released | Online resources https://systemd.io/`)
|
18. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically.
|
||||||
18. [FINAL] Create an empty -stable branch: `git push systemd origin/main:refs/heads/v${version}-stable`.
|
19. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released | Online resources https://systemd.io/`)
|
||||||
19. [FINAL] Build and upload the documentation (on the -stable branch): `ninja -C build doc-sync`
|
20. [FINAL] Create an empty -stable branch: `git push systemd origin/main:refs/heads/v${version}-stable`.
|
||||||
20. [FINAL] Create a new `ci/v${version}-stable` branch for deb package builds on https://salsa.debian.org/systemd-team/systemd
|
21. [FINAL] Build and upload the documentation (on the -stable branch): `ninja -C build doc-sync`
|
||||||
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] Create a new `ci/v${version}-stable` branch for deb package builds on https://salsa.debian.org/systemd-team/systemd
|
||||||
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] Switch `.semaphore/semaphore-runner.sh` and `mkosi/mkosi.pkgenv/mkosi.conf.d/debian-ubuntu.conf`
|
||||||
23. [FINAL] Update version number in `meson.version` to the devel version of the next release (e.g. from `256` to `257~devel`)
|
to the new `ci/v${version}-stable` branch on the -stable branch
|
||||||
24. [FINAL] Build and upload the documentation (on the main branch): `ninja -C build doc-sync`
|
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
|
# Steps to a Successful Stable Release
|
||||||
|
|
||||||
|
|||||||
@ -141,6 +141,17 @@
|
|||||||
<xi:include href="version-info.xml" xpointer="v250"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v250"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</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>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
|||||||
@ -109,13 +109,15 @@
|
|||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--list</option></term>
|
<term><option>--list</option></term>
|
||||||
|
|
||||||
<listitem><para>Lists all active inhibition locks instead of
|
<listitem><para>Lists all active inhibition locks instead of acquiring one. It can be filtered using
|
||||||
acquiring one.</para></listitem>
|
<option>--what=</option>, <option>--who=</option>, <option>--why=</option>, or
|
||||||
|
<option>--mode=</option>.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<xi:include href="standard-options.xml" xpointer="no-ask-password" />
|
<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-pager" />
|
||||||
<xi:include href="standard-options.xml" xpointer="no-legend" />
|
<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="help" />
|
||||||
<xi:include href="standard-options.xml" xpointer="version" />
|
<xi:include href="standard-options.xml" xpointer="version" />
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|||||||
@ -90,6 +90,10 @@
|
|||||||
<entry><constant>ww</constant></entry>
|
<entry><constant>ww</constant></entry>
|
||||||
<entry>Wireless wide area network (WWAN)</entry>
|
<entry>Wireless wide area network (WWAN)</entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><constant>mc</constant></entry>
|
||||||
|
<entry>Management Component Transport Protocol (MCTP)</entry>
|
||||||
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
@ -561,6 +565,16 @@
|
|||||||
<xi:include href="version-info.xml" xpointer="v259"/>
|
<xi:include href="version-info.xml" xpointer="v259"/>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
</variablelist>
|
||||||
|
|
||||||
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
|
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
|
||||||
|
|||||||
@ -354,6 +354,7 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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-pager" />
|
||||||
<xi:include href="standard-options.xml" xpointer="help" />
|
<xi:include href="standard-options.xml" xpointer="help" />
|
||||||
<xi:include href="standard-options.xml" xpointer="version" />
|
<xi:include href="standard-options.xml" xpointer="version" />
|
||||||
|
|||||||
@ -9,5 +9,5 @@ Environment=
|
|||||||
GIT_URL=https://salsa.debian.org/systemd-team/systemd.git
|
GIT_URL=https://salsa.debian.org/systemd-team/systemd.git
|
||||||
GIT_SUBDIR=debian
|
GIT_SUBDIR=debian
|
||||||
GIT_BRANCH=debian/master
|
GIT_BRANCH=debian/master
|
||||||
GIT_COMMIT=efdd7a6377c7251011ca2c1a59115d482d25fe61
|
GIT_COMMIT=6f15bdaae7014c233b662ac4a33d464893b81b36
|
||||||
PKG_SUBDIR=debian
|
PKG_SUBDIR=debian
|
||||||
|
|||||||
@ -10,6 +10,10 @@
|
|||||||
# the Free Software Foundation; either version 2.1 of the License, or
|
# the Free Software Foundation; either version 2.1 of the License, or
|
||||||
# (at your option) any later version.
|
# (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?
|
# Not bash?
|
||||||
[ -n "${BASH_VERSION:-}" ] || return 0
|
[ -n "${BASH_VERSION:-}" ] || return 0
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,7 @@ _varlinkctl() {
|
|||||||
local i n verb comps
|
local i n verb comps
|
||||||
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
|
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||||
local -A OPTS=(
|
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'
|
--oneway --collect --more --exec -j -E'
|
||||||
[ARG]='--graceful --timeout --push-fd --json'
|
[ARG]='--graceful --timeout --push-fd --json'
|
||||||
)
|
)
|
||||||
|
|||||||
@ -3914,7 +3914,7 @@ int bus_exec_context_set_transient_property(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (empty) {
|
if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
|
||||||
bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
|
bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
|
||||||
c->bind_mounts = NULL;
|
c->bind_mounts = NULL;
|
||||||
c->n_bind_mounts = 0;
|
c->n_bind_mounts = 0;
|
||||||
@ -3959,7 +3959,7 @@ int bus_exec_context_set_transient_property(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (empty) {
|
if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
|
||||||
temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
|
temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
|
||||||
c->temporary_filesystems = NULL;
|
c->temporary_filesystems = NULL;
|
||||||
c->n_temporary_filesystems = 0;
|
c->n_temporary_filesystems = 0;
|
||||||
|
|||||||
@ -348,7 +348,7 @@ static void service_start_watchdog(Service *s) {
|
|||||||
log_unit_warning_errno(UNIT(s), r, "Failed to install watchdog timer: %m");
|
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;
|
unsigned n_restarts_next;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|||||||
@ -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);
|
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);
|
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);
|
int service_determine_exec_selinux_label(Service *s, char **ret);
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -18,6 +19,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
|
#include "parse-argument.h"
|
||||||
#include "polkit-agent.h"
|
#include "polkit-agent.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
@ -28,13 +30,14 @@
|
|||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
#include "user-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_who = NULL;
|
||||||
static const char *arg_why = "Unknown reason";
|
static const char *arg_why = NULL;
|
||||||
static const char *arg_mode = NULL;
|
static const char *arg_mode = NULL;
|
||||||
static bool arg_ask_password = true;
|
static bool arg_ask_password = true;
|
||||||
static PagerFlags arg_pager_flags = 0;
|
static PagerFlags arg_pager_flags = 0;
|
||||||
static bool arg_legend = true;
|
static bool arg_legend = true;
|
||||||
|
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
|
||||||
|
|
||||||
static enum {
|
static enum {
|
||||||
ACTION_INHIBIT,
|
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_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||||
_cleanup_(table_unrefp) Table *table = NULL;
|
_cleanup_(table_unrefp) Table *table = NULL;
|
||||||
|
_cleanup_strv_free_ char **what_filter = NULL;
|
||||||
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
pager_open(arg_pager_flags);
|
pager_open(arg_pager_flags);
|
||||||
@ -83,6 +88,12 @@ static int print_inhibitors(sd_bus *bus) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_parse_error(r);
|
return bus_log_parse_error(r);
|
||||||
|
|
||||||
|
if (arg_what) {
|
||||||
|
what_filter = strv_split(arg_what, ":");
|
||||||
|
if (!what_filter)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
_cleanup_free_ char *comm = NULL, *u = NULL;
|
_cleanup_free_ char *comm = NULL, *u = NULL;
|
||||||
const char *what, *who, *why, *mode;
|
const char *what, *who, *why, *mode;
|
||||||
@ -94,6 +105,25 @@ static int print_inhibitors(sd_bus *bus) {
|
|||||||
if (r == 0)
|
if (r == 0)
|
||||||
break;
|
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))
|
if (arg_mode && !streq(mode, arg_mode))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -124,12 +154,12 @@ static int print_inhibitors(sd_bus *bus) {
|
|||||||
|
|
||||||
table_set_header(table, arg_legend);
|
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)
|
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))
|
if (table_isempty(table))
|
||||||
printf("No inhibitors.\n");
|
printf("No inhibitors.\n");
|
||||||
else
|
else
|
||||||
@ -154,6 +184,8 @@ static int help(void) {
|
|||||||
" --no-ask-password Do not attempt interactive authorization\n"
|
" --no-ask-password Do not attempt interactive authorization\n"
|
||||||
" --no-pager Do not pipe output into a pager\n"
|
" --no-pager Do not pipe output into a pager\n"
|
||||||
" --no-legend Do not show the headers and footers\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"
|
" --what=WHAT Operations to inhibit, colon separated list of:\n"
|
||||||
" shutdown, sleep, idle, handle-power-key,\n"
|
" shutdown, sleep, idle, handle-power-key,\n"
|
||||||
" handle-suspend-key, handle-hibernate-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_ASK_PASSWORD,
|
||||||
ARG_NO_PAGER,
|
ARG_NO_PAGER,
|
||||||
ARG_NO_LEGEND,
|
ARG_NO_LEGEND,
|
||||||
|
ARG_JSON,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
@ -196,10 +229,11 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
{ "list", no_argument, NULL, ARG_LIST },
|
{ "list", no_argument, NULL, ARG_LIST },
|
||||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||||
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
|
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
|
||||||
|
{ "json", required_argument, NULL, ARG_JSON },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
int c;
|
int c, r;
|
||||||
|
|
||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
@ -249,6 +283,13 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
arg_legend = false;
|
arg_legend = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_JSON:
|
||||||
|
r = parse_json_argument(optarg, &arg_json_format_flags);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -294,6 +335,9 @@ static int run(int argc, char *argv[]) {
|
|||||||
/* Ignore SIGINT and allow the forked process to receive it */
|
/* Ignore SIGINT and allow the forked process to receive it */
|
||||||
(void) ignore_signals(SIGINT);
|
(void) ignore_signals(SIGINT);
|
||||||
|
|
||||||
|
if (!arg_what)
|
||||||
|
arg_what = "idle:sleep:shutdown";
|
||||||
|
|
||||||
if (!arg_who) {
|
if (!arg_who) {
|
||||||
w = strv_join(argv + optind, " ");
|
w = strv_join(argv + optind, " ");
|
||||||
if (!w)
|
if (!w)
|
||||||
@ -302,6 +346,9 @@ static int run(int argc, char *argv[]) {
|
|||||||
arg_who = w;
|
arg_who = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!arg_why)
|
||||||
|
arg_why = "Unknown reason";
|
||||||
|
|
||||||
if (!arg_mode)
|
if (!arg_mode)
|
||||||
arg_mode = "block";
|
arg_mode = "block";
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
#include "glyph-util.h"
|
#include "glyph-util.h"
|
||||||
#include "in-addr-util.h"
|
#include "in-addr-util.h"
|
||||||
#include "json-util.h"
|
#include "json-util.h"
|
||||||
|
#include "netlink-util.h"
|
||||||
#include "nss-util.h"
|
#include "nss-util.h"
|
||||||
#include "resolved-def.h"
|
#include "resolved-def.h"
|
||||||
#include "signal-util.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);
|
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(
|
enum nss_status _nss_resolve_gethostbyname4_r(
|
||||||
const char *name,
|
const char *name,
|
||||||
struct gaih_addrtuple **pat,
|
struct gaih_addrtuple **pat,
|
||||||
@ -217,7 +235,8 @@ enum nss_status _nss_resolve_gethostbyname4_r(
|
|||||||
r = sd_json_buildo(
|
r = sd_json_buildo(
|
||||||
&cparams,
|
&cparams,
|
||||||
SD_JSON_BUILD_PAIR_STRING("name", name),
|
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)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
@ -386,7 +405,8 @@ enum nss_status _nss_resolve_gethostbyname3_r(
|
|||||||
&cparams,
|
&cparams,
|
||||||
SD_JSON_BUILD_PAIR_STRING("name", name),
|
SD_JSON_BUILD_PAIR_STRING("name", name),
|
||||||
SD_JSON_BUILD_PAIR_INTEGER("family", af),
|
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)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
@ -606,7 +626,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
|
|||||||
&cparams,
|
&cparams,
|
||||||
SD_JSON_BUILD_PAIR_BYTE_ARRAY("address", addr, len),
|
SD_JSON_BUILD_PAIR_BYTE_ARRAY("address", addr, len),
|
||||||
SD_JSON_BUILD_PAIR_INTEGER("family", af),
|
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)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
|||||||
@ -158,13 +158,14 @@ static int verify_features(
|
|||||||
bool *ret_has_rk,
|
bool *ret_has_rk,
|
||||||
bool *ret_has_client_pin,
|
bool *ret_has_client_pin,
|
||||||
bool *ret_has_up,
|
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;
|
_cleanup_(fido_cbor_info_free_wrapper) fido_cbor_info_t *di = NULL;
|
||||||
bool found_extension = false;
|
bool found_extension = false;
|
||||||
char **e, **o;
|
char **e, **o;
|
||||||
const bool *b;
|
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;
|
size_t n;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -205,6 +206,8 @@ static int verify_features(
|
|||||||
has_up = b[i];
|
has_up = b[i];
|
||||||
if (streq(o[i], "uv"))
|
if (streq(o[i], "uv"))
|
||||||
has_uv = b[i];
|
has_uv = b[i];
|
||||||
|
if (streq(o[i], "alwaysUv"))
|
||||||
|
has_always_uv = b[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found_extension)
|
if (!found_extension)
|
||||||
@ -215,11 +218,13 @@ static int verify_features(
|
|||||||
log_debug("Has rk ('Resident Key') support: %s\n"
|
log_debug("Has rk ('Resident Key') support: %s\n"
|
||||||
"Has clientPin support: %s\n"
|
"Has clientPin support: %s\n"
|
||||||
"Has up ('User Presence') 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_rk),
|
||||||
yes_no(has_client_pin),
|
yes_no(has_client_pin),
|
||||||
yes_no(has_up),
|
yes_no(has_up),
|
||||||
yes_no(has_uv));
|
yes_no(has_uv),
|
||||||
|
yes_no(has_always_uv));
|
||||||
|
|
||||||
if (ret_has_rk)
|
if (ret_has_rk)
|
||||||
*ret_has_rk = has_rk;
|
*ret_has_rk = has_rk;
|
||||||
@ -229,6 +234,8 @@ static int verify_features(
|
|||||||
*ret_has_up = has_up;
|
*ret_has_up = has_up;
|
||||||
if (ret_has_uv)
|
if (ret_has_uv)
|
||||||
*ret_has_uv = has_uv;
|
*ret_has_uv = has_uv;
|
||||||
|
if (ret_has_always_uv)
|
||||||
|
*ret_has_always_uv = has_always_uv;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -320,7 +327,7 @@ static int fido2_is_cred_in_specific_token(
|
|||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
"Failed to open FIDO2 device %s: %s", path, sym_fido_strerr(r));
|
"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 */
|
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);
|
log_debug_errno(r, "%s is not a FIDO2 device, or it lacks the hmac-secret extension", path);
|
||||||
return false;
|
return false;
|
||||||
@ -432,7 +439,7 @@ static int fido2_use_hmac_hash_specific_token(
|
|||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
"Failed to open FIDO2 device %s: %s", path, sym_fido_strerr(r));
|
"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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -745,7 +752,7 @@ int fido2_generate_hmac_hash(
|
|||||||
_cleanup_(fido_cred_free_wrapper) fido_cred_t *c = NULL;
|
_cleanup_(fido_cred_free_wrapper) fido_cred_t *c = NULL;
|
||||||
_cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL;
|
_cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL;
|
||||||
_cleanup_(erase_and_freep) char *used_pin = 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;
|
_cleanup_free_ char *cid_copy = NULL;
|
||||||
size_t cid_size, secret_size;
|
size_t cid_size, secret_size;
|
||||||
const void *cid, *secret;
|
const void *cid, *secret;
|
||||||
@ -787,7 +794,7 @@ int fido2_generate_hmac_hash(
|
|||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
"Failed to open FIDO2 device %s: %s", device, sym_fido_strerr(r));
|
"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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -807,6 +814,19 @@ int fido2_generate_hmac_hash(
|
|||||||
lock_with &= ~FIDO2ENROLL_UV;
|
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();
|
c = sym_fido_cred_new();
|
||||||
if (!c)
|
if (!c)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
@ -1124,7 +1144,8 @@ static int check_device_is_fido2_with_hmac_secret(
|
|||||||
bool *ret_has_rk,
|
bool *ret_has_rk,
|
||||||
bool *ret_has_client_pin,
|
bool *ret_has_client_pin,
|
||||||
bool *ret_has_up,
|
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;
|
_cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL;
|
||||||
int r;
|
int r;
|
||||||
@ -1138,9 +1159,9 @@ static int check_device_is_fido2_with_hmac_secret(
|
|||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
"Failed to open FIDO2 device %s: %s", path, sym_fido_strerr(r));
|
"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' */
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1178,7 +1199,7 @@ int fido2_list_devices(void) {
|
|||||||
goto finish;
|
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) {
|
if (!t) {
|
||||||
r = log_oom();
|
r = log_oom();
|
||||||
goto finish;
|
goto finish;
|
||||||
@ -1186,7 +1207,7 @@ int fido2_list_devices(void) {
|
|||||||
|
|
||||||
for (size_t i = 0; i < found; i++) {
|
for (size_t i = 0; i < found; i++) {
|
||||||
const fido_dev_info_t *entry;
|
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);
|
entry = sym_fido_dev_info_ptr(di, i);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
@ -1195,7 +1216,7 @@ int fido2_list_devices(void) {
|
|||||||
goto finish;
|
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)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
bool compatible = r > 0;
|
bool compatible = r > 0;
|
||||||
@ -1209,7 +1230,8 @@ int fido2_list_devices(void) {
|
|||||||
TABLE_BOOLEAN_CHECKMARK, has_rk,
|
TABLE_BOOLEAN_CHECKMARK, has_rk,
|
||||||
TABLE_BOOLEAN_CHECKMARK, has_client_pin,
|
TABLE_BOOLEAN_CHECKMARK, has_client_pin,
|
||||||
TABLE_BOOLEAN_CHECKMARK, has_up,
|
TABLE_BOOLEAN_CHECKMARK, has_up,
|
||||||
TABLE_BOOLEAN_CHECKMARK, has_uv);
|
TABLE_BOOLEAN_CHECKMARK, has_uv,
|
||||||
|
TABLE_BOOLEAN_CHECKMARK, has_always_uv);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
table_log_add_error(r);
|
table_log_add_error(r);
|
||||||
goto finish;
|
goto finish;
|
||||||
@ -1227,7 +1249,8 @@ int fido2_list_devices(void) {
|
|||||||
"%1$sLegend: RK %2$s Resident key%3$s\n"
|
"%1$sLegend: RK %2$s Resident key%3$s\n"
|
||||||
"%1$s CLIENTPIN %2$s PIN request%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 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(),
|
ansi_grey(),
|
||||||
glyph(GLYPH_ARROW_RIGHT),
|
glyph(GLYPH_ARROW_RIGHT),
|
||||||
ansi_normal());
|
ansi_normal());
|
||||||
@ -1287,7 +1310,8 @@ int fido2_find_device_auto(char **ret) {
|
|||||||
/* ret_has_rk= */ NULL,
|
/* ret_has_rk= */ NULL,
|
||||||
/* ret_has_client_pin= */ NULL,
|
/* ret_has_client_pin= */ NULL,
|
||||||
/* ret_has_up= */ NULL,
|
/* ret_has_up= */ NULL,
|
||||||
/* ret_has_uv= */ NULL);
|
/* ret_has_uv= */ NULL,
|
||||||
|
/* ret_has_always_uv= */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
if (!r) {
|
if (!r) {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ static const NamingScheme naming_schemes[] = {
|
|||||||
{ "v257", NAMING_V257 },
|
{ "v257", NAMING_V257 },
|
||||||
{ "v258", NAMING_V258 },
|
{ "v258", NAMING_V258 },
|
||||||
{ "v259", NAMING_V259 },
|
{ "v259", NAMING_V259 },
|
||||||
|
{ "v260", NAMING_V260 },
|
||||||
/* … add more schemes here, as the logic to name devices is updated … */
|
/* … add more schemes here, as the logic to name devices is updated … */
|
||||||
|
|
||||||
EXTRA_NET_NAMING_MAP
|
EXTRA_NET_NAMING_MAP
|
||||||
|
|||||||
@ -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_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_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_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 */
|
/* And now the masks that combine the features above */
|
||||||
NAMING_V238 = 0,
|
NAMING_V238 = 0,
|
||||||
@ -65,6 +66,7 @@ typedef enum NamingSchemeFlags {
|
|||||||
NAMING_V257 = NAMING_V255 | NAMING_FIRMWARE_NODE_SUN | NAMING_DEVICETREE_PORT_ALIASES,
|
NAMING_V257 = NAMING_V255 | NAMING_FIRMWARE_NODE_SUN | NAMING_DEVICETREE_PORT_ALIASES,
|
||||||
NAMING_V258 = NAMING_V257 | NAMING_USE_INTERFACE_PROPERTY,
|
NAMING_V258 = NAMING_V257 | NAMING_USE_INTERFACE_PROPERTY,
|
||||||
NAMING_V259 = NAMING_V258 | NAMING_DEVICETREE_ALIASES_WLAN,
|
NAMING_V259 = NAMING_V258 | NAMING_DEVICETREE_ALIASES_WLAN,
|
||||||
|
NAMING_V260 = NAMING_V259 | NAMING_MCTP,
|
||||||
|
|
||||||
EXTRA_NET_NAMING_SCHEMES
|
EXTRA_NET_NAMING_SCHEMES
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include "bus-polkit.h"
|
||||||
#include "varlink-io.systemd.sysext.h"
|
#include "varlink-io.systemd.sysext.h"
|
||||||
|
|
||||||
static SD_VARLINK_DEFINE_ENUM_TYPE(
|
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_BY_TYPE(class, ImageClass, SD_VARLINK_NULLABLE),
|
||||||
SD_VARLINK_DEFINE_INPUT(force, SD_VARLINK_BOOL, 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(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(
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
Unmerge,
|
Unmerge,
|
||||||
SD_VARLINK_DEFINE_INPUT_BY_TYPE(class, ImageClass, SD_VARLINK_NULLABLE),
|
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(
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
Refresh,
|
Refresh,
|
||||||
SD_VARLINK_DEFINE_INPUT_BY_TYPE(class, ImageClass, SD_VARLINK_NULLABLE),
|
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(force, SD_VARLINK_BOOL, 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),
|
||||||
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(
|
static SD_VARLINK_DEFINE_METHOD_FULL(
|
||||||
List,
|
List,
|
||||||
SD_VARLINK_REQUIRES_MORE,
|
SD_VARLINK_REQUIRES_MORE,
|
||||||
SD_VARLINK_DEFINE_INPUT_BY_TYPE(class, ImageClass, SD_VARLINK_NULLABLE),
|
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(Class, ImageClass, 0),
|
||||||
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(Type, ImageType, 0),
|
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(Type, ImageType, 0),
|
||||||
SD_VARLINK_DEFINE_OUTPUT(Name, SD_VARLINK_STRING, 0),
|
SD_VARLINK_DEFINE_OUTPUT(Name, SD_VARLINK_STRING, 0),
|
||||||
|
|||||||
60
src/sysext/io.systemd.sysext.policy
Normal file
60
src/sysext/io.systemd.sysext.policy
Normal 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>
|
||||||
@ -18,4 +18,7 @@ if conf.get('ENABLE_SYSEXT') == 1
|
|||||||
install_symlink('systemd-confext',
|
install_symlink('systemd-confext',
|
||||||
pointing_to : 'systemd-sysext',
|
pointing_to : 'systemd-sysext',
|
||||||
install_dir : bindir)
|
install_dir : bindir)
|
||||||
|
|
||||||
|
install_data('io.systemd.sysext.policy',
|
||||||
|
install_dir : polkitpolicydir)
|
||||||
endif
|
endif
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
#include "blkid-util.h"
|
#include "blkid-util.h"
|
||||||
#include "blockdev-util.h"
|
#include "blockdev-util.h"
|
||||||
#include "build.h"
|
#include "build.h"
|
||||||
|
#include "bus-polkit.h"
|
||||||
#include "bus-unit-util.h"
|
#include "bus-unit-util.h"
|
||||||
#include "bus-util.h"
|
#include "bus-util.h"
|
||||||
#include "capability-util.h"
|
#include "capability-util.h"
|
||||||
@ -117,6 +118,8 @@ static const struct {
|
|||||||
const char *full_identifier;
|
const char *full_identifier;
|
||||||
const char *short_identifier;
|
const char *short_identifier;
|
||||||
const char *short_identifier_plural;
|
const char *short_identifier_plural;
|
||||||
|
const char *polkit_rw_action_id;
|
||||||
|
const char *polkit_ro_action_id;
|
||||||
const char *blurb;
|
const char *blurb;
|
||||||
const char *dot_directory_name;
|
const char *dot_directory_name;
|
||||||
const char *directory_name;
|
const char *directory_name;
|
||||||
@ -132,6 +135,8 @@ static const struct {
|
|||||||
.full_identifier = "systemd-sysext",
|
.full_identifier = "systemd-sysext",
|
||||||
.short_identifier = "sysext",
|
.short_identifier = "sysext",
|
||||||
.short_identifier_plural = "extensions",
|
.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/.",
|
.blurb = "Merge system extension images into /usr/ and /opt/.",
|
||||||
.dot_directory_name = ".systemd-sysext",
|
.dot_directory_name = ".systemd-sysext",
|
||||||
.level_env = "SYSEXT_LEVEL",
|
.level_env = "SYSEXT_LEVEL",
|
||||||
@ -146,6 +151,8 @@ static const struct {
|
|||||||
.full_identifier = "systemd-confext",
|
.full_identifier = "systemd-confext",
|
||||||
.short_identifier = "confext",
|
.short_identifier = "confext",
|
||||||
.short_identifier_plural = "confexts",
|
.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/.",
|
.blurb = "Merge configuration extension images into /etc/.",
|
||||||
.dot_directory_name = ".systemd-confext",
|
.dot_directory_name = ".systemd-confext",
|
||||||
.level_env = "CONFEXT_LEVEL",
|
.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[] = {
|
static const sd_json_dispatch_field dispatch_table[] = {
|
||||||
{ "class", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MethodUnmergeParameters, class), 0 },
|
{ "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 },
|
{ "noReload", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(MethodUnmergeParameters, no_reload), 0 },
|
||||||
|
VARLINK_DISPATCH_POLKIT_FIELD,
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
MethodUnmergeParameters p = {
|
MethodUnmergeParameters p = {
|
||||||
.no_reload = -1,
|
.no_reload = -1,
|
||||||
};
|
};
|
||||||
|
Hashmap **polkit_registry = ASSERT_PTR(userdata);
|
||||||
_cleanup_strv_free_ char **hierarchies = NULL;
|
_cleanup_strv_free_ char **hierarchies = NULL;
|
||||||
ImageClass image_class = arg_image_class;
|
ImageClass image_class = arg_image_class;
|
||||||
|
bool no_reload;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
@ -638,13 +648,24 @@ static int vl_method_unmerge(sd_varlink *link, sd_json_variant *parameters, sd_v
|
|||||||
if (r != 0)
|
if (r != 0)
|
||||||
return r;
|
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);
|
r = parse_image_class_parameter(link, p.class, &image_class, &hierarchies);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = unmerge(image_class,
|
r = varlink_verify_polkit_async(
|
||||||
hierarchies ?: arg_hierarchies,
|
link,
|
||||||
p.no_reload >= 0 ? p.no_reload : arg_no_reload);
|
/* 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)
|
if (r < 0)
|
||||||
return r;
|
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 },
|
{ "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 },
|
{ "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 },
|
{ "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) {
|
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;
|
_cleanup_hashmap_free_ Hashmap *images = NULL;
|
||||||
MethodMergeParameters p = {
|
MethodMergeParameters p = {
|
||||||
.force = -1,
|
.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;
|
_cleanup_strv_free_ char **hierarchies = NULL;
|
||||||
ImageClass image_class = arg_image_class;
|
ImageClass image_class = arg_image_class;
|
||||||
int r;
|
bool force, no_reload;
|
||||||
|
int r, noexec;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
@ -2292,6 +2316,23 @@ static int vl_method_merge(sd_varlink *link, sd_json_variant *parameters, sd_var
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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);
|
r = image_discover_and_read_metadata(image_class, &images);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -2306,12 +2347,7 @@ static int vl_method_merge(sd_varlink *link, sd_json_variant *parameters, sd_var
|
|||||||
if (r > 0)
|
if (r > 0)
|
||||||
return sd_varlink_errorbo(link, "io.systemd.sysext.AlreadyMerged", SD_JSON_BUILD_PAIR_STRING("hierarchy", which));
|
return sd_varlink_errorbo(link, "io.systemd.sysext.AlreadyMerged", SD_JSON_BUILD_PAIR_STRING("hierarchy", which));
|
||||||
|
|
||||||
r = merge(image_class,
|
r = merge(image_class, hierarchies ?: arg_hierarchies, force, no_reload, noexec, images);
|
||||||
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);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -2381,9 +2417,11 @@ static int vl_method_refresh(sd_varlink *link, sd_json_variant *parameters, sd_v
|
|||||||
.no_reload = -1,
|
.no_reload = -1,
|
||||||
.noexec = -1,
|
.noexec = -1,
|
||||||
};
|
};
|
||||||
|
Hashmap **polkit_registry = ASSERT_PTR(userdata);
|
||||||
_cleanup_strv_free_ char **hierarchies = NULL;
|
_cleanup_strv_free_ char **hierarchies = NULL;
|
||||||
ImageClass image_class = arg_image_class;
|
ImageClass image_class = arg_image_class;
|
||||||
int r;
|
bool force, no_reload;
|
||||||
|
int r, noexec;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
@ -2395,11 +2433,24 @@ static int vl_method_refresh(sd_varlink *link, sd_json_variant *parameters, sd_v
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = refresh(image_class,
|
force = p.force >= 0 ? p.force : arg_force;
|
||||||
hierarchies ?: arg_hierarchies,
|
no_reload = p.no_reload >= 0 ? p.no_reload : arg_no_reload;
|
||||||
p.force >= 0 ? p.force : arg_force,
|
noexec = p.noexec >= 0 ? p.noexec : arg_noexec;
|
||||||
p.no_reload >= 0 ? p.no_reload : arg_no_reload,
|
|
||||||
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)
|
if (r < 0)
|
||||||
return r;
|
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[] = {
|
static const sd_json_dispatch_field dispatch_table[] = {
|
||||||
{ "class", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, 0 },
|
{ "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;
|
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||||
|
Hashmap **polkit_registry = ASSERT_PTR(userdata);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
@ -2462,6 +2515,15 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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;
|
_cleanup_hashmap_free_ Hashmap *images = NULL;
|
||||||
r = image_discover(RUNTIME_SCOPE_SYSTEM, image_class, arg_root, &images);
|
r = image_discover(RUNTIME_SCOPE_SYSTEM, image_class, arg_root, &images);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -2727,10 +2789,14 @@ static int run(int argc, char *argv[]) {
|
|||||||
|
|
||||||
if (arg_varlink) {
|
if (arg_varlink) {
|
||||||
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL;
|
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL;
|
||||||
|
_cleanup_hashmap_free_ Hashmap *polkit_registry = NULL;
|
||||||
|
|
||||||
/* Invocation as Varlink service */
|
/* 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)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to allocate Varlink server: %m");
|
return log_error_errno(r, "Failed to allocate Varlink server: %m");
|
||||||
|
|
||||||
|
|||||||
@ -1307,7 +1307,7 @@ static int get_ifname_prefix(sd_device *dev, const char **ret) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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) {
|
switch (iftype) {
|
||||||
case ARPHRD_ETHER: {
|
case ARPHRD_ETHER: {
|
||||||
if (device_is_devtype(dev, "wlan") > 0)
|
if (device_is_devtype(dev, "wlan") > 0)
|
||||||
@ -1329,6 +1329,13 @@ static int get_ifname_prefix(sd_device *dev, const char **ret) {
|
|||||||
*ret = "sl";
|
*ret = "sl";
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
case ARPHRD_MCTP:
|
||||||
|
if (!naming_scheme_has(NAMING_MCTP))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
*ret = "mc";
|
||||||
|
return 0;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "sd-varlink.h"
|
#include "sd-varlink.h"
|
||||||
|
|
||||||
#include "build.h"
|
#include "build.h"
|
||||||
|
#include "bus-util.h"
|
||||||
#include "env-util.h"
|
#include "env-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
@ -21,6 +22,7 @@
|
|||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "pidfd-util.h"
|
#include "pidfd-util.h"
|
||||||
|
#include "polkit-agent.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
@ -46,6 +48,7 @@ static char **arg_graceful = NULL;
|
|||||||
static usec_t arg_timeout = 0;
|
static usec_t arg_timeout = 0;
|
||||||
static bool arg_exec = false;
|
static bool arg_exec = false;
|
||||||
static PushFds arg_push_fds = {};
|
static PushFds arg_push_fds = {};
|
||||||
|
static bool arg_ask_password = true;
|
||||||
|
|
||||||
static void push_fds_done(PushFds *p) {
|
static void push_fds_done(PushFds *p) {
|
||||||
assert(p);
|
assert(p);
|
||||||
@ -87,6 +90,7 @@ static int help(void) {
|
|||||||
"\n%3$sOptions:%4$s\n"
|
"\n%3$sOptions:%4$s\n"
|
||||||
" -h --help Show this help\n"
|
" -h --help Show this help\n"
|
||||||
" --version Show package version\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"
|
" --no-pager Do not pipe output into a pager\n"
|
||||||
" --more Request multiple responses\n"
|
" --more Request multiple responses\n"
|
||||||
" --collect Collect multiple responses in a JSON array\n"
|
" --collect Collect multiple responses in a JSON array\n"
|
||||||
@ -126,21 +130,23 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
ARG_TIMEOUT,
|
ARG_TIMEOUT,
|
||||||
ARG_EXEC,
|
ARG_EXEC,
|
||||||
ARG_PUSH_FD,
|
ARG_PUSH_FD,
|
||||||
|
ARG_NO_ASK_PASSWORD,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "version", no_argument, NULL, ARG_VERSION },
|
{ "version", no_argument, NULL, ARG_VERSION },
|
||||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||||
{ "more", no_argument, NULL, ARG_MORE },
|
{ "more", no_argument, NULL, ARG_MORE },
|
||||||
{ "oneway", no_argument, NULL, ARG_ONEWAY },
|
{ "oneway", no_argument, NULL, ARG_ONEWAY },
|
||||||
{ "json", required_argument, NULL, ARG_JSON },
|
{ "json", required_argument, NULL, ARG_JSON },
|
||||||
{ "collect", no_argument, NULL, ARG_COLLECT },
|
{ "collect", no_argument, NULL, ARG_COLLECT },
|
||||||
{ "quiet", no_argument, NULL, 'q' },
|
{ "quiet", no_argument, NULL, 'q' },
|
||||||
{ "graceful", required_argument, NULL, ARG_GRACEFUL },
|
{ "graceful", required_argument, NULL, ARG_GRACEFUL },
|
||||||
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
|
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
|
||||||
{ "exec", no_argument, NULL, ARG_EXEC },
|
{ "exec", no_argument, NULL, ARG_EXEC },
|
||||||
{ "push-fd", required_argument, NULL, ARG_PUSH_FD },
|
{ "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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ARG_NO_ASK_PASSWORD:
|
||||||
|
arg_ask_password = false;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return -EINVAL;
|
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)
|
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.");
|
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];
|
url = argv[1];
|
||||||
method = argv[2];
|
method = argv[2];
|
||||||
parameter = argc > 3 && !streq(argv[3], "-") ? argv[3] : NULL;
|
parameter = argc > 3 && !streq(argv[3], "-") ? argv[3] : NULL;
|
||||||
|
|||||||
@ -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 '{}'
|
varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Unmerge '{}'
|
||||||
(! grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file )
|
(! 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
|
# Check that extensions cannot contain os-release
|
||||||
mkdir -p /run/extensions/app-reject/usr/lib/{extension-release.d/,systemd/system}
|
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
|
echo "ID=_any" >/run/extensions/app-reject/usr/lib/extension-release.d/extension-release.app-reject
|
||||||
|
|||||||
@ -26,6 +26,8 @@ at_exit() {
|
|||||||
|
|
||||||
rm -rf "$IMAGE_DIR"
|
rm -rf "$IMAGE_DIR"
|
||||||
|
|
||||||
|
rm -f /etc/polkit-1/rules.d/sysext-unpriv.rules
|
||||||
|
|
||||||
loginctl disable-linger testuser
|
loginctl disable-linger testuser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ ConditionCapability=CAP_SYS_ADMIN
|
|||||||
[Socket]
|
[Socket]
|
||||||
ListenStream=/run/systemd/io.systemd.sysext
|
ListenStream=/run/systemd/io.systemd.sysext
|
||||||
FileDescriptorName=varlink
|
FileDescriptorName=varlink
|
||||||
SocketMode=0600
|
SocketMode=0666
|
||||||
Accept=yes
|
Accept=yes
|
||||||
MaxConnectionsPerSource=16
|
MaxConnectionsPerSource=16
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user