Compare commits

...

29 Commits

Author SHA1 Message Date
Ronan Pigott 77409a848a
Merge d4f1b642c2 into b7eefa1996 2024-11-21 17:04:30 +00:00
Luca Boccassi b7eefa1996 cgroup-util: fix memory leak on error
CID#1565824

Follow-up for f6793bbcf0
2024-11-21 14:02:34 +09:00
Luca Boccassi 2e5b0412f9
network: update state files before replying bus method (#35255)
Follow-up for 2b07a3211b.

Fixes the failure found in
https://autopkgtest.ubuntu.com/results/autopkgtest-noble-upstream-systemd-ci-systemd-ci/noble/amd64/s/systemd-upstream/20241115_182040_92382@/log.gz
. Relevant logs:
```
Nov 16 02:48:36 systemd-networkd[2706]: veth99: Reconfiguring with /run/systemd/network/25-dhcp-client-ipv6-only.network.
Nov 16 02:48:36 systemd-networkd[2706]: veth99: NDISC: Started IPv6 Router Solicitation client
Nov 16 02:48:36 systemd-networkd[2706]: veth99: IPv6 Router Discovery is configured and started.
Nov 16 02:48:36 systemd-networkd[2706]: veth99: NDISC: Sent Router Solicitation, next solicitation in 3s
Nov 16 02:48:36 systemd-networkd[2706]: veth99: NDISC: Received Router Advertisement from fe80::1034:56ff:fe78:9abd: flags=0xc0(managed, other), preference=medium, lifetime=30min
Nov 16 02:48:36 systemd-networkd[2706]: veth99: NDISC: Invoking callback for 'router' event.
Nov 16 02:48:36 systemd-networkd[2706]: veth99: link_check_ready(): dynamic addressing protocols are enabled but none of them finished yet.
Nov 16 02:48:36 systemd-networkd[2706]: veth99: DHCPv6 client: Starting in Solicit mode
Nov 16 02:48:36 systemd-networkd[2706]: veth99: DHCPv6 client: State changed: stopped -> solicitation
Nov 16 02:48:36 systemd-networkd[2706]: veth99: Acquiring DHCPv6 lease on NDisc request
Nov 16 02:48:36 systemd-networkd[2706]: veth99: DHCPv6 client: Sent Solicit
Nov 16 02:48:36 systemd-networkd[2706]: veth99: DHCPv6 client: Next retransmission in 1s
Nov 16 02:48:37 systemd-networkd[2706]: veth99: DHCPv6 client: Sent Solicit
Nov 16 02:48:37 systemd-networkd[2706]: veth99: DHCPv6 client: Next retransmission in 1s
Nov 16 02:48:39 systemd-networkd[2706]: veth99: NDISC: Received Neighbor Advertisement from fe80::1034:56ff:fe78:9abd: Router=yes, Solicited=yes, Override=no
Nov 16 02:48:39 systemd-networkd[2706]: veth99: NDISC: Invoking callback for 'neighbor' event.
Nov 16 02:48:39 systemd-networkd[2706]: veth99: DHCPv6 client: Processed Reply message
Nov 16 02:48:39 systemd-networkd[2706]: veth99: DHCPv6 client: T1 expires in 50s
Nov 16 02:48:39 systemd-networkd[2706]: veth99: DHCPv6 client: T2 expires in 55s
Nov 16 02:48:39 systemd-networkd[2706]: veth99: DHCPv6 client: Valid lifetime expires in 2min
Nov 16 02:48:39 systemd-networkd[2706]: veth99: DHCPv6 client: State changed: solicitation -> bound
Nov 16 02:48:39 systemd-networkd[2706]: veth99: DHCPv6 address 2600::15/128 (valid for 1min 59s, preferred for 1min 59s)
Nov 16 02:48:41 systemd-networkd[2706]: veth99: Received updated DHCPv6 address (configured): 2600::15/128 (valid for 1min 58s, preferred for 1min 58s), flags: no-prefixroute, scope: global
Nov 16 02:48:41 systemd-networkd[2706]: veth99: DHCPv6 addresses and routes set.
Nov 16 02:48:41 systemd-networkd[2706]: veth99: link_check_ready(): IPv4LL:no DHCPv4:no DHCPv6:yes DHCP-PD:no NDisc:no
Nov 16 02:48:41 systemd-networkd[2706]: veth99: State changed: configuring -> configured
```
The interface veth99 entered the configured state after 5 seconds, but
at the same time, the `wait_online()` in the test script considered the
test failed.
The function `wait_online()` first invokes
`systemd-networkd-wait-online` with `--timeout=20`, then check setup
states of interfaces with 5 seconds timeout. So, the failure suggests
that `systemd-networkd-wait-online` finishes immediately, as the state
file was not updated when it is invoked, and thus it handles the
interface veth99 already in the configured state.
2024-11-20 23:36:35 +00:00
Martin Srebotnjak 69af4849aa po: Translated using Weblate (Slovenian)
Currently translated at 100.0% (257 of 257 strings)

Co-authored-by: Martin Srebotnjak <miles@filmsi.net>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/sl/
Translation: systemd/main
2024-11-21 04:17:08 +09:00
Jiri Grönroos 18d4e0be89 po: Translated using Weblate (Finnish)
Currently translated at 100.0% (257 of 257 strings)

Co-authored-by: Jiri Grönroos <jiri.gronroos@iki.fi>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/fi/
Translation: systemd/main
2024-11-21 04:17:08 +09:00
Dmytro Markevych 7d7b89a015 po: Translated using Weblate (Ukrainian)
Currently translated at 100.0% (257 of 257 strings)

Co-authored-by: Dmytro Markevych <hotr1pak@gmail.com>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/uk/
Translation: systemd/main
2024-11-21 04:17:08 +09:00
Léane GRASSER 8a92365f79 po: Translated using Weblate (French)
Currently translated at 100.0% (257 of 257 strings)

Co-authored-by: Léane GRASSER <leane.grasser@proton.me>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/fr/
Translation: systemd/main
2024-11-21 04:17:08 +09:00
Yu Watanabe 2b397d43ab test-network: actually check metric and preference
Otherwise, nexthop ID may contain e.g. 300, then
===
AssertionError: '300' unexpectedly found in
'default nhid 3860882700 via fe80::1034:56ff:fe78:9a99 proto ra metric 512 expires 1798sec pref high\n
 default nhid 2639230080 via fe80::1034:56ff:fe78:9a98 proto ra metric 2048 expires 1798sec pref low'
===
2024-11-21 03:43:35 +09:00
Yu Watanabe 9ad294efd0 network: update state files before replying bus method
Follow-up for 2b07a3211b.
2024-11-21 03:42:06 +09:00
Lennart Poettering f6793bbcf0 killall: gracefully handle processes inserted into containers via nsenter -a
"nsenter -a" doesn't migrate the specified process into the target
cgroup (it really should). Thus the cgroup will remain in a cgroup
that is (due to cgroup ns) outside our visibility. The kernel will
report the cgroup path of such cgroups as starting with "/../". Detect
that and print a reasonably error message instead of trying to resolve
that.
2024-11-20 18:11:38 +00:00
Mike Yuan f87863a8ff process-util: refuse to operate on remote PidRef
Follow-up for 7e3e540b88
2024-11-20 18:10:26 +00:00
Antonio Alvarez Feijoo 58c3c2886d cryptenroll: fix typo 2024-11-20 18:03:44 +00:00
Daan De Meyer dbbe895807 test-audit-util: Migrate to new assertion macros 2024-11-20 16:48:55 +00:00
Yu Watanabe 52b0351a15
core/exec-invoke: suppress placeholder home only in build_environment() (#35219)
Alternative to https://github.com/systemd/systemd/pull/34789
Closes #34789
2024-11-20 17:34:25 +09:00
Luca Boccassi fe077a1a58 units: add initrd directory to list of conditions for systemd-confext
systemd-sysext has the same check, but it was forgotten for confexts.
Needed to activate confexts from the ESP in the initrd.
2024-11-20 09:12:24 +01:00
Xuanjun Wen a526b9ddfc hwdb: add new Cube Mix Plus (i18D) rotation info
Added rotation information for the new version of Cube Mix Plus (i18D).
2024-11-20 05:23:34 +09:00
Mike Yuan 804dd670d1
sd-varlink: mark sd_varlink_server_{ref,unref} as _public_ (#35241)
Co-authored-by: Thorsten Kukuk <kukuk@suse.com>
2024-11-20 05:21:15 +09:00
Mike Yuan b718b86e1b
core/exec-invoke: suppress placeholder home only in build_environment()
Currently, get_fixed_user() employs USER_CREDS_SUPPRESS_PLACEHOLDER,
meaning home path is set to NULL if it's empty or root. However,
the path is also used for applying WorkingDirectory=~, and we'd
spuriously use the invoking user's home as fallback even if
User= is changed in that case.

Let's instead delegate such suppression to build_environment(),
so that home is proper initialized for usage at other steps.
shell doesn't actually suffer from such problem, but it's changed
too for consistency.

Alternative to #34789
2024-11-19 00:38:18 +01:00
Mike Yuan d911778877
core/exec-invoke: minor cleanup for apply_working_directory() error handling
Assign exit_status at the same site where error log is emitted,
for readability.
2024-11-19 00:38:18 +01:00
Mike Yuan eea9d3eb10
basic/user-util: split out placeholder suppression from USER_CREDS_CLEAN into its own flag
No functional change, preparation for later commits.
2024-11-19 00:38:18 +01:00
Mike Yuan 579ce77ead
basic/user-util: introduce shell_is_placeholder() helper 2024-11-19 00:38:18 +01:00
Ronan Pigott d4f1b642c2 pam: add session class "none" to disable logind sessions
pam_systemd is used to create logind sessions and to apply extended
attributes from json user records. Not every application that creates a
pam session expects a login scope, but may be interested in the extended
attributes of json user records. Session class "none" implements this
service by disabling logind for this session altogether.
2024-11-15 11:38:19 -07:00
Lennart Poettering 65250fac6a pam_systemd: introduce pam_get_data_many() helper and make use of it
This is to pam_get_data() what pam_get_item() is to pam_get_item_many().
2024-11-15 15:23:41 +01:00
Lennart Poettering 5d8efe440e pam_systemd: fix error code confusion when prepping D-Bus message
We got confused by the error codes here, and sometimes return PAM errors
where the caller propagated them unconverted as negative errno errors. Fix that.
2024-11-15 15:10:58 +01:00
Lennart Poettering 524f0d14e1 pam_systemd: split pam_sm_open_session() into more digestable blocks
Let's separate four different parts of pam_sm_open_session():

1. Acquiring of our various parameters from pam env, pam data, pam items
2. Mangling of that data to clean it up
3. Registering of the service with logind
4. Importing shell credentials into environment variables
5. Enforcement of user record data

This makes the code a lot more readable, and gets rid of an ugly got
label.

It also corrects things: if step 3 doesnt work because logind is not
around, we'll now still do step 4, which we previously erroneously
skipped.

Besodes that no real code changes.
2024-11-15 15:10:56 +01:00
Lennart Poettering ae40305e65 pam_systemd: split out setting of shell env vars from credentials and move it later
Let's shorten the code of pam_sm_open_session() a bit, and also make
sure the importing of the env vars from the creds also happens if the
session registration with logind is skipped.
2024-11-15 15:10:53 +01:00
Lennart Poettering ceb5d4cc73 pam_systemd: drop "uid" field from SessionContext
Let's instead just pass over the UserRecord, it's a much more useful
object with lots more information we'll sooner or later need
(preparation for later commits).
2024-11-15 15:10:51 +01:00
Lennart Poettering 68b0318194 pam_systemd: drop "pid" field from SessionContext
We never use the field and this is not going to change...

This recomes a weird asymmetry, as create_session_message() always went
to the process' own PID when ding pidfds but otherwise took the pid as
input.
2024-11-15 15:10:48 +01:00
Lennart Poettering 51160b6bca pam-systemd: normalize parsing of XDG_VTNR
Let's make it more like the parsing of the "incomplete" boolean env var,
to streamline things.
2024-11-15 15:10:46 +01:00
26 changed files with 540 additions and 406 deletions

View File

@ -376,11 +376,12 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svncube:pni1-TF:*
sensor:modalias:acpi:SMO8500*:dmi:*:svncube:pni7:* sensor:modalias:acpi:SMO8500*:dmi:*:svncube:pni7:*
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1 ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
# Cube i7 Stylus, i7 Stylus I8L Model, i7 Book (i16) and Mix Plus (i18B) # Cube i7 Stylus, i7 Stylus I8L Model, i7 Book (i16) and Mix Plus (i18B/i18D)
sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni7Stylus:* sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni7Stylus:*
sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni8-L:* sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni8-L:*
sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni16:* sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni16:*
sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni18B:* sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni18B:*
sensor:modalias:acpi:KIOX000A*:dmi:*:svnALLDOCUBE:pni18D:*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
# Cube iWork 10 Flagship # Cube iWork 10 Flagship

View File

@ -143,6 +143,10 @@
<entry><constant>manager-early</constant></entry> <entry><constant>manager-early</constant></entry>
<entry>Similar to <constant>manager</constant>, but for the root user. Compare with the <constant>user</constant> vs. <constant>user-early</constant> situation. (Added in v256.)</entry> <entry>Similar to <constant>manager</constant>, but for the root user. Compare with the <constant>user</constant> vs. <constant>user-early</constant> situation. (Added in v256.)</entry>
</row> </row>
<row>
<entry><constant>none</constant></entry>
<entry>Skips registering this session with logind. No session scope will be created, and the user service manager will not be started. (Added in v258.)</entry>
</row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>

View File

@ -3,12 +3,13 @@
# Finnish translation of systemd. # Finnish translation of systemd.
# Jan Kuparinen <copper_fin@hotmail.com>, 2021, 2022, 2023. # Jan Kuparinen <copper_fin@hotmail.com>, 2021, 2022, 2023.
# Ricky Tigg <ricky.tigg@gmail.com>, 2022, 2024. # Ricky Tigg <ricky.tigg@gmail.com>, 2022, 2024.
# Jiri Grönroos <jiri.gronroos@iki.fi>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 14:42+0000\n" "POT-Creation-Date: 2024-11-06 14:42+0000\n"
"PO-Revision-Date: 2024-09-12 13:43+0000\n" "PO-Revision-Date: 2024-11-20 19:13+0000\n"
"Last-Translator: Ricky Tigg <ricky.tigg@gmail.com>\n" "Last-Translator: Jiri Grönroos <jiri.gronroos@iki.fi>\n"
"Language-Team: Finnish <https://translate.fedoraproject.org/projects/systemd/" "Language-Team: Finnish <https://translate.fedoraproject.org/projects/systemd/"
"main/fi/>\n" "main/fi/>\n"
"Language: fi\n" "Language: fi\n"
@ -16,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.7.2\n" "X-Generator: Weblate 5.8.2\n"
#: src/core/org.freedesktop.systemd1.policy.in:22 #: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system" msgid "Send passphrase back to system"
@ -112,14 +113,12 @@ msgid "Authentication is required to update a user's home area."
msgstr "Todennus vaaditaan käyttäjän kotialueen päivittämiseksi." msgstr "Todennus vaaditaan käyttäjän kotialueen päivittämiseksi."
#: src/home/org.freedesktop.home1.policy:53 #: src/home/org.freedesktop.home1.policy:53
#, fuzzy
msgid "Update your home area" msgid "Update your home area"
msgstr "Päivitä kotialue" msgstr "Päivitä kotialue"
#: src/home/org.freedesktop.home1.policy:54 #: src/home/org.freedesktop.home1.policy:54
#, fuzzy
msgid "Authentication is required to update your home area." msgid "Authentication is required to update your home area."
msgstr "Todennus vaaditaan käyttäjän kotialueen päivittämiseksi." msgstr "Todennus vaaditaan kotialueen päivittämiseksi."
#: src/home/org.freedesktop.home1.policy:63 #: src/home/org.freedesktop.home1.policy:63
msgid "Resize a home area" msgid "Resize a home area"
@ -1174,14 +1173,11 @@ msgstr "Todennus vaaditaan vanhojen järjestelmäpäivitysten puhdistamiseen."
#: src/sysupdate/org.freedesktop.sysupdate1.policy:75 #: src/sysupdate/org.freedesktop.sysupdate1.policy:75
msgid "Manage optional features" msgid "Manage optional features"
msgstr "" msgstr "Hallitse valinnaisia ominaisuuksia"
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76 #: src/sysupdate/org.freedesktop.sysupdate1.policy:76
#, fuzzy
msgid "Authentication is required to manage optional features" msgid "Authentication is required to manage optional features"
msgstr "" msgstr "Todennus vaaditaan valinnaisten ominaisuuksien hallintaan"
"Todennus vaaditaan aktiivisten istuntojen, käyttäjien ja paikkojen "
"hallintaan."
#: src/timedate/org.freedesktop.timedate1.policy:22 #: src/timedate/org.freedesktop.timedate1.policy:22
msgid "Set system time" msgid "Set system time"

View File

@ -12,7 +12,7 @@ msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 14:42+0000\n" "POT-Creation-Date: 2024-11-06 14:42+0000\n"
"PO-Revision-Date: 2024-11-07 09:30+0000\n" "PO-Revision-Date: 2024-11-20 19:13+0000\n"
"Last-Translator: Léane GRASSER <leane.grasser@proton.me>\n" "Last-Translator: Léane GRASSER <leane.grasser@proton.me>\n"
"Language-Team: French <https://translate.fedoraproject.org/projects/systemd/" "Language-Team: French <https://translate.fedoraproject.org/projects/systemd/"
"main/fr/>\n" "main/fr/>\n"
@ -360,8 +360,8 @@ msgid ""
"Authentication is required to set the statically configured local hostname, " "Authentication is required to set the statically configured local hostname, "
"as well as the pretty hostname." "as well as the pretty hostname."
msgstr "" msgstr ""
"Une authentification est requise pour définir le nom d'hôte local de manière " "Une authentification est requise pour définir le nom d'hôte local configuré "
"statique, ainsi que le nom d'hôte familier." "de manière statique, ainsi que le nom d'hôte convivial."
#: src/hostname/org.freedesktop.hostname1.policy:41 #: src/hostname/org.freedesktop.hostname1.policy:41
msgid "Set machine information" msgid "Set machine information"

View File

@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: systemd\n" "Project-Id-Version: systemd\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 14:42+0000\n" "POT-Creation-Date: 2024-11-06 14:42+0000\n"
"PO-Revision-Date: 2024-08-26 19:38+0000\n" "PO-Revision-Date: 2024-11-20 19:13+0000\n"
"Last-Translator: Martin Srebotnjak <miles@filmsi.net>\n" "Last-Translator: Martin Srebotnjak <miles@filmsi.net>\n"
"Language-Team: Slovenian <https://translate.fedoraproject.org/projects/" "Language-Team: Slovenian <https://translate.fedoraproject.org/projects/"
"systemd/main/sl/>\n" "systemd/main/sl/>\n"
@ -17,7 +17,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || " "Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || "
"n%100==4 ? 2 : 3;\n" "n%100==4 ? 2 : 3;\n"
"X-Generator: Weblate 5.7\n" "X-Generator: Weblate 5.8.2\n"
#: src/core/org.freedesktop.systemd1.policy.in:22 #: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system" msgid "Send passphrase back to system"
@ -125,16 +125,13 @@ msgstr ""
"območja." "območja."
#: src/home/org.freedesktop.home1.policy:53 #: src/home/org.freedesktop.home1.policy:53
#, fuzzy
msgid "Update your home area" msgid "Update your home area"
msgstr "Posodobite domače območje" msgstr "Posodobite domače območje"
#: src/home/org.freedesktop.home1.policy:54 #: src/home/org.freedesktop.home1.policy:54
#, fuzzy
msgid "Authentication is required to update your home area." msgid "Authentication is required to update your home area."
msgstr "" msgstr ""
"Preverjanje pristnosti je potrebno za posodobitev uporabnikovega domačega " "Preverjanje pristnosti je potrebno za posodobitev vašega domačega območja."
"območja."
#: src/home/org.freedesktop.home1.policy:63 #: src/home/org.freedesktop.home1.policy:63
msgid "Resize a home area" msgid "Resize a home area"
@ -1234,14 +1231,12 @@ msgstr ""
#: src/sysupdate/org.freedesktop.sysupdate1.policy:75 #: src/sysupdate/org.freedesktop.sysupdate1.policy:75
msgid "Manage optional features" msgid "Manage optional features"
msgstr "" msgstr "Upravljaj dodatne funkcionalnosti"
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76 #: src/sysupdate/org.freedesktop.sysupdate1.policy:76
#, fuzzy
msgid "Authentication is required to manage optional features" msgid "Authentication is required to manage optional features"
msgstr "" msgstr ""
"Preverjanje pristnosti je potrebno za upravljanje aktivnih sej, uporabnikov " "Preverjanje pristnosti je potrebno za upravljanje dodatnih funkcionalnosti."
"in delovišč."
#: src/timedate/org.freedesktop.timedate1.policy:22 #: src/timedate/org.freedesktop.timedate1.policy:22
msgid "Set system time" msgid "Set system time"

View File

@ -4,12 +4,13 @@
# Eugene Melnik <jeka7js@gmail.com>, 2014. # Eugene Melnik <jeka7js@gmail.com>, 2014.
# Daniel Korostil <ted.korostiled@gmail.com>, 2014, 2016, 2018. # Daniel Korostil <ted.korostiled@gmail.com>, 2014, 2016, 2018.
# Yuri Chornoivan <yurchor@ukr.net>, 2019, 2020, 2021, 2022, 2023, 2024. # Yuri Chornoivan <yurchor@ukr.net>, 2019, 2020, 2021, 2022, 2023, 2024.
# Dmytro Markevych <hotr1pak@gmail.com>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 14:42+0000\n" "POT-Creation-Date: 2024-11-06 14:42+0000\n"
"PO-Revision-Date: 2024-08-24 10:36+0000\n" "PO-Revision-Date: 2024-11-20 19:13+0000\n"
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n" "Last-Translator: Dmytro Markevych <hotr1pak@gmail.com>\n"
"Language-Team: Ukrainian <https://translate.fedoraproject.org/projects/" "Language-Team: Ukrainian <https://translate.fedoraproject.org/projects/"
"systemd/main/uk/>\n" "systemd/main/uk/>\n"
"Language: uk\n" "Language: uk\n"
@ -18,7 +19,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.7\n" "X-Generator: Weblate 5.8.2\n"
#: src/core/org.freedesktop.systemd1.policy.in:22 #: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system" msgid "Send passphrase back to system"
@ -118,14 +119,12 @@ msgid "Authentication is required to update a user's home area."
msgstr "Для оновлення домашньої теки користувача слід пройти розпізнавання." msgstr "Для оновлення домашньої теки користувача слід пройти розпізнавання."
#: src/home/org.freedesktop.home1.policy:53 #: src/home/org.freedesktop.home1.policy:53
#, fuzzy
msgid "Update your home area" msgid "Update your home area"
msgstr "Оновлення домашньої теки" msgstr "Оновіть свій домашній простір"
#: src/home/org.freedesktop.home1.policy:54 #: src/home/org.freedesktop.home1.policy:54
#, fuzzy
msgid "Authentication is required to update your home area." msgid "Authentication is required to update your home area."
msgstr "Для оновлення домашньої теки користувача слід пройти розпізнавання." msgstr "Для оновлення домашньої області потрібна автентифікація."
#: src/home/org.freedesktop.home1.policy:63 #: src/home/org.freedesktop.home1.policy:63
msgid "Resize a home area" msgid "Resize a home area"
@ -1212,14 +1211,11 @@ msgstr "Для вилучення застарілих оновлень сист
#: src/sysupdate/org.freedesktop.sysupdate1.policy:75 #: src/sysupdate/org.freedesktop.sysupdate1.policy:75
msgid "Manage optional features" msgid "Manage optional features"
msgstr "" msgstr "Керування додатковими функціями"
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76 #: src/sysupdate/org.freedesktop.sysupdate1.policy:76
#, fuzzy
msgid "Authentication is required to manage optional features" msgid "Authentication is required to manage optional features"
msgstr "" msgstr "Для керування додатковими функціями потрібна автентифікація"
"Для того, щоб керувати сеансами, користувачами і робочими місцями, слід "
"пройти розпізнавання."
#: src/timedate/org.freedesktop.timedate1.policy:22 #: src/timedate/org.freedesktop.timedate1.policy:22
msgid "Set system time" msgid "Set system time"

View File

@ -799,16 +799,20 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **ret_path) {
continue; continue;
} }
char *path = strdup(e + 1); _cleanup_free_ char *path = strdup(e + 1);
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
/* Refuse cgroup paths from outside our cgroup namespace */
if (startswith(path, "/../"))
return -EUNATCH;
/* Truncate suffix indicating the process is a zombie */ /* Truncate suffix indicating the process is a zombie */
e = endswith(path, " (deleted)"); e = endswith(path, " (deleted)");
if (e) if (e)
*e = 0; *e = 0;
*ret_path = path; *ret_path = TAKE_PTR(path);
return 0; return 0;
} }
} }

View File

@ -102,8 +102,8 @@ int pid_get_comm(pid_t pid, char **ret) {
_cleanup_free_ char *escaped = NULL, *comm = NULL; _cleanup_free_ char *escaped = NULL, *comm = NULL;
int r; int r;
assert(ret);
assert(pid >= 0); assert(pid >= 0);
assert(ret);
if (pid == 0 || pid == getpid_cached()) { if (pid == 0 || pid == getpid_cached()) {
comm = new0(char, TASK_COMM_LEN + 1); /* Must fit in 16 byte according to prctl(2) */ comm = new0(char, TASK_COMM_LEN + 1); /* Must fit in 16 byte according to prctl(2) */
@ -143,6 +143,9 @@ int pidref_get_comm(const PidRef *pid, char **ret) {
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_comm(pid->pid, &comm); r = pid_get_comm(pid->pid, &comm);
if (r < 0) if (r < 0)
return r; return r;
@ -289,6 +292,9 @@ int pidref_get_cmdline(const PidRef *pid, size_t max_columns, ProcessCmdlineFlag
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_cmdline(pid->pid, max_columns, flags, &s); r = pid_get_cmdline(pid->pid, max_columns, flags, &s);
if (r < 0) if (r < 0)
return r; return r;
@ -331,6 +337,9 @@ int pidref_get_cmdline_strv(const PidRef *pid, ProcessCmdlineFlags flags, char *
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_cmdline_strv(pid->pid, flags, &args); r = pid_get_cmdline_strv(pid->pid, flags, &args);
if (r < 0) if (r < 0)
return r; return r;
@ -477,6 +486,9 @@ int pidref_is_kernel_thread(const PidRef *pid) {
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
result = pid_is_kernel_thread(pid->pid); result = pid_is_kernel_thread(pid->pid);
if (result < 0) if (result < 0)
return result; return result;
@ -594,6 +606,9 @@ int pidref_get_uid(const PidRef *pid, uid_t *ret) {
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_uid(pid->pid, &uid); r = pid_get_uid(pid->pid, &uid);
if (r < 0) if (r < 0)
return r; return r;
@ -794,6 +809,9 @@ int pidref_get_start_time(const PidRef *pid, usec_t *ret) {
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_start_time(pid->pid, ret ? &t : NULL); r = pid_get_start_time(pid->pid, ret ? &t : NULL);
if (r < 0) if (r < 0)
return r; return r;
@ -1093,6 +1111,9 @@ int pidref_is_my_child(const PidRef *pid) {
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
result = pid_is_my_child(pid->pid); result = pid_is_my_child(pid->pid);
if (result < 0) if (result < 0)
return result; return result;
@ -1128,6 +1149,9 @@ int pidref_is_unwaited(const PidRef *pid) {
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
if (pid->pid == 1 || pidref_is_self(pid)) if (pid->pid == 1 || pidref_is_self(pid))
return true; return true;
@ -1169,6 +1193,9 @@ int pidref_is_alive(const PidRef *pidref) {
if (!pidref_is_set(pidref)) if (!pidref_is_set(pidref))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pidref))
return -EREMOTE;
result = pid_is_alive(pidref->pid); result = pid_is_alive(pidref->pid);
if (result < 0) { if (result < 0) {
assert(result != -ESRCH); assert(result != -ESRCH);

View File

@ -220,9 +220,9 @@ static int synthesize_user_creds(
if (ret_gid) if (ret_gid)
*ret_gid = GID_NOBODY; *ret_gid = GID_NOBODY;
if (ret_home) if (ret_home)
*ret_home = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : "/"; *ret_home = FLAGS_SET(flags, USER_CREDS_SUPPRESS_PLACEHOLDER) ? NULL : "/";
if (ret_shell) if (ret_shell)
*ret_shell = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : NOLOGIN; *ret_shell = FLAGS_SET(flags, USER_CREDS_SUPPRESS_PLACEHOLDER) ? NULL : NOLOGIN;
return 0; return 0;
} }
@ -244,6 +244,7 @@ int get_user_creds(
assert(username); assert(username);
assert(*username); assert(*username);
assert((ret_home || ret_shell) || !(flags & (USER_CREDS_SUPPRESS_PLACEHOLDER|USER_CREDS_CLEAN)));
if (!FLAGS_SET(flags, USER_CREDS_PREFER_NSS) || if (!FLAGS_SET(flags, USER_CREDS_PREFER_NSS) ||
(!ret_home && !ret_shell)) { (!ret_home && !ret_shell)) {
@ -315,17 +316,14 @@ int get_user_creds(
if (ret_home) if (ret_home)
/* Note: we don't insist on normalized paths, since there are setups that have /./ in the path */ /* Note: we don't insist on normalized paths, since there are setups that have /./ in the path */
*ret_home = (FLAGS_SET(flags, USER_CREDS_CLEAN) && *ret_home = (FLAGS_SET(flags, USER_CREDS_SUPPRESS_PLACEHOLDER) && empty_or_root(p->pw_dir)) ||
(empty_or_root(p->pw_dir) || (FLAGS_SET(flags, USER_CREDS_CLEAN) && (!path_is_valid(p->pw_dir) || !path_is_absolute(p->pw_dir)))
!path_is_valid(p->pw_dir) || ? NULL : p->pw_dir;
!path_is_absolute(p->pw_dir))) ? NULL : p->pw_dir;
if (ret_shell) if (ret_shell)
*ret_shell = (FLAGS_SET(flags, USER_CREDS_CLEAN) && *ret_shell = (FLAGS_SET(flags, USER_CREDS_SUPPRESS_PLACEHOLDER) && shell_is_placeholder(p->pw_shell)) ||
(isempty(p->pw_shell) || (FLAGS_SET(flags, USER_CREDS_CLEAN) && (!path_is_valid(p->pw_shell) || !path_is_absolute(p->pw_shell)))
!path_is_valid(p->pw_shell) || ? NULL : p->pw_shell;
!path_is_absolute(p->pw_shell) ||
is_nologin_shell(p->pw_shell))) ? NULL : p->pw_shell;
if (patch_username) if (patch_username)
*username = p->pw_name; *username = p->pw_name;

View File

@ -12,6 +12,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "string-util.h"
/* Users managed by systemd-homed. See https://systemd.io/UIDS-GIDS for details how this range fits into the rest of the world */ /* Users managed by systemd-homed. See https://systemd.io/UIDS-GIDS for details how this range fits into the rest of the world */
#define HOME_UID_MIN ((uid_t) 60001) #define HOME_UID_MIN ((uid_t) 60001)
#define HOME_UID_MAX ((uid_t) 60513) #define HOME_UID_MAX ((uid_t) 60513)
@ -36,10 +38,20 @@ static inline int parse_gid(const char *s, gid_t *ret_gid) {
char* getlogname_malloc(void); char* getlogname_malloc(void);
char* getusername_malloc(void); char* getusername_malloc(void);
const char* default_root_shell_at(int rfd);
const char* default_root_shell(const char *root);
bool is_nologin_shell(const char *shell);
static inline bool shell_is_placeholder(const char *shell) {
return isempty(shell) || is_nologin_shell(shell);
}
typedef enum UserCredsFlags { typedef enum UserCredsFlags {
USER_CREDS_PREFER_NSS = 1 << 0, /* if set, only synthesize user records if database lacks them. Normally we bypass the userdb entirely for the records we can synthesize */ USER_CREDS_PREFER_NSS = 1 << 0, /* if set, only synthesize user records if database lacks them. Normally we bypass the userdb entirely for the records we can synthesize */
USER_CREDS_ALLOW_MISSING = 1 << 1, /* if a numeric UID string is resolved, be OK if there's no record for it */ USER_CREDS_ALLOW_MISSING = 1 << 1, /* if a numeric UID string is resolved, be OK if there's no record for it */
USER_CREDS_CLEAN = 1 << 2, /* try to clean up shell and home fields with invalid data */ USER_CREDS_CLEAN = 1 << 2, /* try to clean up shell and home fields with invalid data */
USER_CREDS_SUPPRESS_PLACEHOLDER = 1 << 3, /* suppress home and/or shell fields if value is placeholder (root/empty/nologin) */
} UserCredsFlags; } UserCredsFlags;
int get_user_creds(const char **username, uid_t *ret_uid, gid_t *ret_gid, const char **ret_home, const char **ret_shell, UserCredsFlags flags); int get_user_creds(const char **username, uid_t *ret_uid, gid_t *ret_gid, const char **ret_home, const char **ret_shell, UserCredsFlags flags);
@ -125,10 +137,6 @@ int fgetsgent_sane(FILE *stream, struct sgrp **sg);
int putsgent_sane(const struct sgrp *sg, FILE *stream); int putsgent_sane(const struct sgrp *sg, FILE *stream);
#endif #endif
bool is_nologin_shell(const char *shell);
const char* default_root_shell_at(int rfd);
const char* default_root_shell(const char *root);
int is_this_me(const char *username); int is_this_me(const char *username);
const char* get_home_root(void); const char* get_home_root(void);

View File

@ -855,9 +855,6 @@ static int get_fixed_user(
assert(user_or_uid); assert(user_or_uid);
assert(ret_username); assert(ret_username);
/* Note that we don't set $HOME or $SHELL if they are not particularly enlightening anyway
* (i.e. are "/" or "/bin/nologin"). */
r = get_user_creds(&user_or_uid, ret_uid, ret_gid, ret_home, ret_shell, USER_CREDS_CLEAN); r = get_user_creds(&user_or_uid, ret_uid, ret_gid, ret_home, ret_shell, USER_CREDS_CLEAN);
if (r < 0) if (r < 0)
return r; return r;
@ -1883,7 +1880,10 @@ static int build_environment(
} }
} }
if (home && set_user_login_env) { /* Note that we don't set $HOME or $SHELL if they are not particularly enlightening anyway
* (i.e. are "/" or "/bin/nologin"). */
if (home && set_user_login_env && !empty_or_root(home)) {
x = strjoin("HOME=", home); x = strjoin("HOME=", home);
if (!x) if (!x)
return -ENOMEM; return -ENOMEM;
@ -1892,7 +1892,7 @@ static int build_environment(
our_env[n_env++] = x; our_env[n_env++] = x;
} }
if (shell && set_user_login_env) { if (shell && set_user_login_env && !shell_is_placeholder(shell)) {
x = strjoin("SHELL=", shell); x = strjoin("SHELL=", shell);
if (!x) if (!x)
return -ENOMEM; return -ENOMEM;
@ -3471,20 +3471,16 @@ static int apply_working_directory(
const ExecContext *context, const ExecContext *context,
const ExecParameters *params, const ExecParameters *params,
ExecRuntime *runtime, ExecRuntime *runtime,
const char *home, const char *home) {
int *exit_status) {
const char *wd; const char *wd;
int r; int r;
assert(context); assert(context);
assert(exit_status);
if (context->working_directory_home) { if (context->working_directory_home) {
if (!home) { if (!home)
*exit_status = EXIT_CHDIR;
return -ENXIO; return -ENXIO;
}
wd = home; wd = home;
} else } else
@ -3503,13 +3499,7 @@ static int apply_working_directory(
if (r >= 0) if (r >= 0)
r = RET_NERRNO(fchdir(dfd)); r = RET_NERRNO(fchdir(dfd));
} }
return context->working_directory_missing_ok ? 0 : r;
if (r < 0 && !context->working_directory_missing_ok) {
*exit_status = EXIT_CHDIR;
return r;
}
return 0;
} }
static int apply_root_directory( static int apply_root_directory(
@ -3785,7 +3775,7 @@ static int acquire_home(const ExecContext *c, const char **home, char **ret_buf)
if (!c->working_directory_home) if (!c->working_directory_home)
return 0; return 0;
if (c->dynamic_user) if (c->dynamic_user || (c->user && is_this_me(c->user) <= 0))
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
r = get_home_dir(ret_buf); r = get_home_dir(ret_buf);
@ -4543,7 +4533,7 @@ int exec_invoke(
r = acquire_home(context, &home, &home_buffer); r = acquire_home(context, &home, &home_buffer);
if (r < 0) { if (r < 0) {
*exit_status = EXIT_CHDIR; *exit_status = EXIT_CHDIR;
return log_exec_error_errno(context, params, r, "Failed to determine $HOME for user: %m"); return log_exec_error_errno(context, params, r, "Failed to determine $HOME for the invoking user: %m");
} }
/* If a socket is connected to STDIN/STDOUT/STDERR, we must drop O_NONBLOCK */ /* If a socket is connected to STDIN/STDOUT/STDERR, we must drop O_NONBLOCK */
@ -5382,9 +5372,11 @@ int exec_invoke(
* running this service might have the correct privilege to change to the working directory. Also, it * running this service might have the correct privilege to change to the working directory. Also, it
* is absolutely 💣 crucial 💣 we applied all mount namespacing rearrangements before this, so that * is absolutely 💣 crucial 💣 we applied all mount namespacing rearrangements before this, so that
* the cwd cannot be used to pin directories outside of the sandbox. */ * the cwd cannot be used to pin directories outside of the sandbox. */
r = apply_working_directory(context, params, runtime, home, exit_status); r = apply_working_directory(context, params, runtime, home);
if (r < 0) if (r < 0) {
*exit_status = EXIT_CHDIR;
return log_exec_error_errno(context, params, r, "Changing to the requested working directory failed: %m"); return log_exec_error_errno(context, params, r, "Changing to the requested working directory failed: %m");
}
if (needs_sandboxing) { if (needs_sandboxing) {
/* Apply other MAC contexts late, but before seccomp syscall filtering, as those should really be last to /* Apply other MAC contexts late, but before seccomp syscall filtering, as those should really be last to

View File

@ -193,7 +193,7 @@ int enroll_fido2(
fflush(stdout); fflush(stdout);
fprintf(stderr, fprintf(stderr,
"\nPlease save this FIDO2 credential ID. It is required when unloocking the volume\n" "\nPlease save this FIDO2 credential ID. It is required when unlocking the volume\n"
"using the associated FIDO2 keyslot which we just created. To configure automatic\n" "using the associated FIDO2 keyslot which we just created. To configure automatic\n"
"unlocking using this FIDO2 token, add an appropriate entry to your /etc/crypttab\n" "unlocking using this FIDO2 token, add an appropriate entry to your /etc/crypttab\n"
"file, see %s for details.\n", link); "file, see %s for details.\n", link);

View File

@ -1033,12 +1033,14 @@ global:
sd_varlink_server_listen_fd; sd_varlink_server_listen_fd;
sd_varlink_server_loop_auto; sd_varlink_server_loop_auto;
sd_varlink_server_new; sd_varlink_server_new;
sd_varlink_server_ref;
sd_varlink_server_set_connections_max; sd_varlink_server_set_connections_max;
sd_varlink_server_set_connections_per_uid_max; sd_varlink_server_set_connections_per_uid_max;
sd_varlink_server_set_description; sd_varlink_server_set_description;
sd_varlink_server_set_exit_on_idle; sd_varlink_server_set_exit_on_idle;
sd_varlink_server_set_userdata; sd_varlink_server_set_userdata;
sd_varlink_server_shutdown; sd_varlink_server_shutdown;
sd_varlink_server_unref;
sd_varlink_set_allow_fd_passing_input; sd_varlink_set_allow_fd_passing_input;
sd_varlink_set_allow_fd_passing_output; sd_varlink_set_allow_fd_passing_output;
sd_varlink_set_description; sd_varlink_set_description;

View File

@ -3265,7 +3265,7 @@ static sd_varlink_server* varlink_server_destroy(sd_varlink_server *s) {
return mfree(s); return mfree(s);
} }
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_varlink_server, sd_varlink_server, varlink_server_destroy); DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_varlink_server, sd_varlink_server, varlink_server_destroy);
static int validate_connection(sd_varlink_server *server, const struct ucred *ucred) { static int validate_connection(sd_varlink_server *server, const struct ucred *ucred) {
int allowed = -1; int allowed = -1;

View File

@ -863,6 +863,27 @@ static int create_session(
if (!uid_is_valid(uid)) if (!uid_is_valid(uid))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UID"); return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UID");
if (isempty(type))
t = _SESSION_TYPE_INVALID;
else {
t = session_type_from_string(type);
if (t < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Invalid session type %s", type);
}
if (isempty(class))
c = _SESSION_CLASS_INVALID;
else {
c = session_class_from_string(class);
if (c < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Invalid session class %s", class);
if (c == SESSION_NONE)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Refusing session class %s", class);
}
if (flags != 0) if (flags != 0)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be zero."); return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be zero.");
@ -882,24 +903,6 @@ static int create_session(
if (leader.pid == 1 || leader.pid == getpid_cached()) if (leader.pid == 1 || leader.pid == getpid_cached())
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID"); return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
if (isempty(type))
t = _SESSION_TYPE_INVALID;
else {
t = session_type_from_string(type);
if (t < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Invalid session type %s", type);
}
if (isempty(class))
c = _SESSION_CLASS_INVALID;
else {
c = session_class_from_string(class);
if (c < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Invalid session class %s", class);
}
if (isempty(desktop)) if (isempty(desktop))
desktop = NULL; desktop = NULL;
else { else {

View File

@ -29,6 +29,7 @@ typedef enum SessionClass {
SESSION_BACKGROUND_LIGHT, /* Like SESSION_BACKGROUND, but without the service manager */ SESSION_BACKGROUND_LIGHT, /* Like SESSION_BACKGROUND, but without the service manager */
SESSION_MANAGER, /* The service manager */ SESSION_MANAGER, /* The service manager */
SESSION_MANAGER_EARLY, /* The service manager for root (which is allowed to run before systemd-user-sessions.service) */ SESSION_MANAGER_EARLY, /* The service manager for root (which is allowed to run before systemd-user-sessions.service) */
SESSION_NONE, /* A session not registered with logind */
_SESSION_CLASS_MAX, _SESSION_CLASS_MAX,
_SESSION_CLASS_INVALID = -EINVAL, _SESSION_CLASS_INVALID = -EINVAL,
} SessionClass; } SessionClass;
@ -44,7 +45,7 @@ typedef enum SessionClass {
#define SESSION_CLASS_WANTS_SERVICE_MANAGER(class) IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_GREETER, SESSION_LOCK_SCREEN, SESSION_BACKGROUND) #define SESSION_CLASS_WANTS_SERVICE_MANAGER(class) IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_GREETER, SESSION_LOCK_SCREEN, SESSION_BACKGROUND)
/* Which session classes can pin our user tracking? */ /* Which session classes can pin our user tracking? */
#define SESSION_CLASS_PIN_USER(class) (!IN_SET((class), SESSION_MANAGER, SESSION_MANAGER_EARLY)) #define SESSION_CLASS_PIN_USER(class) (!IN_SET((class), SESSION_MANAGER, SESSION_MANAGER_EARLY, SESSION_NONE))
/* Which session classes decide whether system is idle? (should only cover sessions that have input, and are not idle screens themselves)*/ /* Which session classes decide whether system is idle? (should only cover sessions that have input, and are not idle screens themselves)*/
#define SESSION_CLASS_CAN_IDLE(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_GREETER)) #define SESSION_CLASS_CAN_IDLE(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_GREETER))

View File

@ -390,116 +390,108 @@ static int export_legacy_dbus_address(
} }
static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) { static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
uint64_t val;
int r; int r;
assert(handle);
assert(m);
if (isempty(limit)) if (isempty(limit))
return PAM_SUCCESS; return 0;
if (streq(limit, "infinity")) { if (streq(limit, "infinity"))
r = sd_bus_message_append(m, "(sv)", "MemoryMax", "t", UINT64_MAX); return sd_bus_message_append(m, "(sv)", "MemoryMax", "t", UINT64_MAX);
if (r < 0)
return pam_bus_log_create_error(handle, r);
return PAM_SUCCESS;
}
r = parse_permyriad(limit); r = parse_permyriad(limit);
if (r >= 0) { if (r < 0) {
r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", UINT32_SCALE_FROM_PERMYRIAD(r)); uint64_t val;
if (r < 0) r = parse_size(limit, 1024, &val);
return pam_bus_log_create_error(handle, r); if (r < 0) {
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.memory_max, ignoring: %s", limit);
return PAM_SUCCESS;
}
return PAM_SUCCESS; return sd_bus_message_append(m, "(sv)", "MemoryMax", "t", val);
} }
r = parse_size(limit, 1024, &val); return sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", UINT32_SCALE_FROM_PERMYRIAD(r));
if (r >= 0) {
r = sd_bus_message_append(m, "(sv)", "MemoryMax", "t", val);
if (r < 0)
return pam_bus_log_create_error(handle, r);
return PAM_SUCCESS;
}
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.memory_max, ignoring: %s", limit);
return PAM_SUCCESS;
} }
static int append_session_runtime_max_sec(pam_handle_t *handle, sd_bus_message *m, const char *limit) { static int append_session_runtime_max_sec(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
usec_t val;
int r; int r;
assert(handle);
assert(m);
/* No need to parse "infinity" here, it will be set by default later in scope_init() */ /* No need to parse "infinity" here, it will be set by default later in scope_init() */
if (isempty(limit) || streq(limit, "infinity")) if (isempty(limit) || streq(limit, "infinity"))
return PAM_SUCCESS; return 0;
usec_t val;
r = parse_sec(limit, &val); r = parse_sec(limit, &val);
if (r >= 0) { if (r < 0) {
r = sd_bus_message_append(m, "(sv)", "RuntimeMaxUSec", "t", (uint64_t) val);
if (r < 0)
return pam_bus_log_create_error(handle, r);
} else
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.runtime_max_sec: %s, ignoring.", limit); pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.runtime_max_sec: %s, ignoring.", limit);
return 0;
}
return PAM_SUCCESS; return sd_bus_message_append(m, "(sv)", "RuntimeMaxUSec", "t", (uint64_t) val);
} }
static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) { static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
uint64_t val;
int r; int r;
assert(handle);
assert(m);
/* No need to parse "infinity" here, it will be set unconditionally later in manager_start_scope() */ /* No need to parse "infinity" here, it will be set unconditionally later in manager_start_scope() */
if (isempty(limit) || streq(limit, "infinity")) if (isempty(limit) || streq(limit, "infinity"))
return PAM_SUCCESS; return 0;
uint64_t val;
r = safe_atou64(limit, &val); r = safe_atou64(limit, &val);
if (r >= 0) { if (r < 0) {
r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", val);
if (r < 0)
return pam_bus_log_create_error(handle, r);
} else
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.tasks_max, ignoring: %s", limit); pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.tasks_max, ignoring: %s", limit);
return 0;
}
return PAM_SUCCESS; return sd_bus_message_append(m, "(sv)", "TasksMax", "t", val);
} }
static int append_session_cpu_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit) { static int append_session_cpu_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
uint64_t val;
int r; int r;
if (isempty(limit)) assert(handle);
return PAM_SUCCESS; assert(m);
if (isempty(limit))
return 0;
uint64_t val;
r = cg_cpu_weight_parse(limit, &val); r = cg_cpu_weight_parse(limit, &val);
if (r < 0) if (r < 0) {
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight, ignoring: %s", limit); pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight, ignoring: %s", limit);
else { return 0;
r = sd_bus_message_append(m, "(sv)", "CPUWeight", "t", val);
if (r < 0)
return pam_bus_log_create_error(handle, r);
} }
return PAM_SUCCESS; return sd_bus_message_append(m, "(sv)", "CPUWeight", "t", val);
} }
static int append_session_io_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit) { static int append_session_io_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
uint64_t val;
int r; int r;
if (isempty(limit)) assert(handle);
return PAM_SUCCESS; assert(m);
if (isempty(limit))
return 0;
uint64_t val;
r = cg_weight_parse(limit, &val); r = cg_weight_parse(limit, &val);
if (r < 0) if (r < 0) {
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight, ignoring: %s", limit); pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight, ignoring: %s", limit);
else { return 0;
r = sd_bus_message_append(m, "(sv)", "IOWeight", "t", val);
if (r < 0)
return pam_bus_log_create_error(handle, r);
} }
return PAM_SUCCESS; return sd_bus_message_append(m, "(sv)", "IOWeight", "t", val);
} }
static const char* getenv_harder(pam_handle_t *handle, const char *key, const char *fallback) { static const char* getenv_harder(pam_handle_t *handle, const char *key, const char *fallback) {
@ -549,6 +541,26 @@ static bool getenv_harder_bool(pam_handle_t *handle, const char *key, bool fallb
return r; return r;
} }
static uint32_t getenv_harder_uint32(pam_handle_t *handle, const char *key, uint32_t fallback) {
int r;
assert(handle);
assert(key);
const char *v = getenv_harder(handle, key, NULL);
if (isempty(v))
return fallback;
uint32_t u;
r = safe_atou32(v, &u);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Unsigned integer environment variable value of '%s' is not valid: %s", key, v);
return fallback;
}
return u;
}
static int update_environment(pam_handle_t *handle, const char *key, const char *value) { static int update_environment(pam_handle_t *handle, const char *key, const char *value) {
int r; int r;
@ -826,17 +838,15 @@ static uint64_t pick_default_capability_ambient_set(
} }
typedef struct SessionContext { typedef struct SessionContext {
const uid_t uid;
const pid_t pid;
const char *service; const char *service;
const char *type; const char *type;
const char *class; const char *class;
const char *desktop; const char *desktop;
const char *seat; const char *seat;
const uint32_t vtnr; uint32_t vtnr;
const char *tty; const char *tty;
const char *display; const char *display;
const bool remote; bool remote;
const char *remote_user; const char *remote_user;
const char *remote_host; const char *remote_host;
const char *memory_max; const char *memory_max;
@ -844,11 +854,13 @@ typedef struct SessionContext {
const char *cpu_weight; const char *cpu_weight;
const char *io_weight; const char *io_weight;
const char *runtime_max_sec; const char *runtime_max_sec;
bool incomplete;
} SessionContext; } SessionContext;
static int create_session_message( static int create_session_message(
sd_bus *bus, sd_bus *bus,
pam_handle_t *handle, pam_handle_t *handle,
UserRecord *ur,
const SessionContext *context, const SessionContext *context,
bool avoid_pidfd, bool avoid_pidfd,
sd_bus_message **ret) { sd_bus_message **ret) {
@ -859,6 +871,7 @@ static int create_session_message(
assert(bus); assert(bus);
assert(handle); assert(handle);
assert(ur);
assert(context); assert(context);
assert(ret); assert(ret);
@ -872,21 +885,22 @@ static int create_session_message(
if (r < 0) if (r < 0)
return r; return r;
r = sd_bus_message_append(m, r = sd_bus_message_append(
pidfd >= 0 ? "uhsssssussbss" : "uusssssussbss", m,
(uint32_t) context->uid, pidfd >= 0 ? "uhsssssussbss" : "uusssssussbss",
pidfd >= 0 ? pidfd : context->pid, (uint32_t) ur->uid,
context->service, pidfd >= 0 ? pidfd : 0,
context->type, context->service,
context->class, context->type,
context->desktop, context->class,
context->seat, context->desktop,
context->vtnr, context->seat,
context->tty, context->vtnr,
context->display, context->tty,
context->remote, context->display,
context->remote_user, context->remote,
context->remote_host); context->remote_user,
context->remote_host);
if (r < 0) if (r < 0)
return r; return r;
@ -901,23 +915,23 @@ static int create_session_message(
return r; return r;
r = append_session_memory_max(handle, m, context->memory_max); r = append_session_memory_max(handle, m, context->memory_max);
if (r != PAM_SUCCESS) if (r < 0)
return r; return r;
r = append_session_runtime_max_sec(handle, m, context->runtime_max_sec); r = append_session_runtime_max_sec(handle, m, context->runtime_max_sec);
if (r != PAM_SUCCESS) if (r < 0)
return r; return r;
r = append_session_tasks_max(handle, m, context->tasks_max); r = append_session_tasks_max(handle, m, context->tasks_max);
if (r != PAM_SUCCESS) if (r < 0)
return r; return r;
r = append_session_cpu_weight(handle, m, context->cpu_weight); r = append_session_cpu_weight(handle, m, context->cpu_weight);
if (r != PAM_SUCCESS) if (r < 0)
return r; return r;
r = append_session_io_weight(handle, m, context->io_weight); r = append_session_io_weight(handle, m, context->io_weight);
if (r != PAM_SUCCESS) if (r < 0)
return r; return r;
r = sd_bus_message_close_container(m); r = sd_bus_message_close_container(m);
@ -928,10 +942,93 @@ static int create_session_message(
return 0; return 0;
} }
_public_ PAM_EXTERN int pam_sm_open_session( static void session_context_mangle(
pam_handle_t *handle, pam_handle_t *handle,
int flags, SessionContext *c,
int argc, const char **argv) { UserRecord *ur,
bool debug) {
assert(handle);
assert(c);
assert(ur);
if (streq_ptr(c->service, "systemd-user")) {
/* If we detect that we are running in the "systemd-user" PAM stack, then let's patch the class to
* 'manager' if not set, simply for robustness reasons. */
c->type = "unspecified";
c->class = IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC) ?
"manager-early" : "manager";
c->tty = NULL;
} else if (c->tty && strchr(c->tty, ':')) {
/* A tty with a colon is usually an X11 display, placed there to show up in utmp. We rearrange things
* and don't pretend that an X display was a tty. */
if (isempty(c->display))
c->display = c->tty;
c->tty = NULL;
} else if (streq_ptr(c->tty, "cron")) {
/* cron is setting PAM_TTY to "cron" for some reason (the commit carries no information why, but
* probably because it wants to set it to something as pam_time/pam_access/ require PAM_TTY to be set
* (as they otherwise even try to update it!) but cron doesn't actually allocate a TTY for its forked
* off processes.) */
c->type = "unspecified";
c->class = "background";
c->tty = NULL;
} else if (streq_ptr(c->tty, "ssh")) {
/* ssh has been setting PAM_TTY to "ssh" (for the same reason as cron does this, see above. For further
* details look for "PAM_TTY_KLUDGE" in the openssh sources). */
c->type = "tty";
c->class = "user";
c->tty = NULL; /* This one is particularly sad, as this means that ssh sessions — even though
* usually associated with a pty won't be tracked by their tty in
* logind. This is because ssh does the PAM session registration early for new
* connections, and registers a pty only much later (this is because it doesn't
* know yet if it needs one at all, as whether to register a pty or not is
* negotiated much later in the protocol). */
} else if (c->tty)
/* Chop off leading /dev prefix that some clients specify, but others do not. */
c->tty = skip_dev_prefix(c->tty);
if (!isempty(c->display) && !c->vtnr) {
if (isempty(c->seat))
(void) get_seat_from_display(c->display, &c->seat, &c->vtnr);
else if (streq(c->seat, "seat0"))
(void) get_seat_from_display(c->display, /* seat= */ NULL, &c->vtnr);
}
if (c->seat && !streq(c->seat, "seat0") && c->vtnr != 0) {
pam_debug_syslog(handle, debug, "Ignoring vtnr %"PRIu32" for %s which is not seat0", c->vtnr, c->seat);
c->vtnr = 0;
}
if (isempty(c->type))
c->type = !isempty(c->display) ? "x11" :
!isempty(c->tty) ? "tty" : "unspecified";
if (isempty(c->class))
c->class = streq(c->type, "unspecified") ? "background" :
((IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC) &&
streq(c->type, "tty")) ? "user-early" : "user");
if (c->incomplete) {
if (streq(c->class, "user"))
c->class = "user-incomplete";
else
pam_syslog_pam_error(handle, LOG_WARNING, 0, "PAM session of class '%s' is incomplete, which is not supported, ignoring.", c->class);
}
c->remote = !isempty(c->remote_host) && !is_localhost(c->remote_host);
}
static int register_session(
pam_handle_t *handle,
SessionContext *c,
UserRecord *ur,
bool debug,
char **ret_seat) {
/* Let's release the D-Bus connection once this function exits, after all the session might live /* Let's release the D-Bus connection once this function exits, after all the session might live
* quite a long time, and we are not going to process the bus connection in that time, so let's * quite a long time, and we are not going to process the bus connection in that time, so let's
@ -939,152 +1036,21 @@ _public_ PAM_EXTERN int pam_sm_open_session(
_cleanup_(pam_bus_data_disconnectp) PamBusData *d = NULL; _cleanup_(pam_bus_data_disconnectp) PamBusData *d = NULL;
_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 *m = NULL, *reply = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
const char
*id, *object_path, *runtime_path,
*service = NULL,
*tty = NULL, *display = NULL,
*remote_user = NULL, *remote_host = NULL,
*seat = NULL,
*type = NULL, *class = NULL,
*class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL, *desktop_pam = NULL,
*memory_max = NULL, *tasks_max = NULL, *cpu_weight = NULL, *io_weight = NULL, *runtime_max_sec = NULL;
uint64_t default_capability_bounding_set = UINT64_MAX, default_capability_ambient_set = UINT64_MAX;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(user_record_unrefp) UserRecord *ur = NULL; int r;
int session_fd = -EBADF, existing, r;
bool debug = false, remote, incomplete;
uint32_t vtnr = 0;
uid_t original_uid;
assert(handle); assert(handle);
assert(c);
pam_log_setup(); assert(ur);
assert(ret_seat);
if (parse_argv(handle,
argc, argv,
&class_pam,
&type_pam,
&desktop_pam,
&debug,
&default_capability_bounding_set,
&default_capability_ambient_set) < 0)
return PAM_SESSION_ERR;
pam_debug_syslog(handle, debug, "pam-systemd initializing");
r = acquire_user_record(handle, &ur);
if (r != PAM_SUCCESS)
return r;
/* Make most of this a NOP on non-logind systems */ /* Make most of this a NOP on non-logind systems */
if (!logind_running()) if (!logind_running())
goto success; goto skip;
r = pam_get_item_many( /* We don't register session class none with logind */
handle, if (streq(c->class, "none"))
PAM_SERVICE, &service, goto skip;
PAM_XDISPLAY, &display,
PAM_TTY, &tty,
PAM_RUSER, &remote_user,
PAM_RHOST, &remote_host);
if (r != PAM_SUCCESS)
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM items: @PAMERR@");
seat = getenv_harder(handle, "XDG_SEAT", NULL);
cvtnr = getenv_harder(handle, "XDG_VTNR", NULL);
type = getenv_harder(handle, "XDG_SESSION_TYPE", type_pam);
class = getenv_harder(handle, "XDG_SESSION_CLASS", class_pam);
desktop = getenv_harder(handle, "XDG_SESSION_DESKTOP", desktop_pam);
incomplete = getenv_harder_bool(handle, "XDG_SESSION_INCOMPLETE", false);
if (streq_ptr(service, "systemd-user")) {
/* If we detect that we are running in the "systemd-user" PAM stack, then let's patch the class to
* 'manager' if not set, simply for robustness reasons. */
type = "unspecified";
class = IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC) ?
"manager-early" : "manager";
tty = NULL;
} else if (tty && strchr(tty, ':')) {
/* A tty with a colon is usually an X11 display, placed there to show up in utmp. We rearrange things
* and don't pretend that an X display was a tty. */
if (isempty(display))
display = tty;
tty = NULL;
} else if (streq_ptr(tty, "cron")) {
/* cron is setting PAM_TTY to "cron" for some reason (the commit carries no information why, but
* probably because it wants to set it to something as pam_time/pam_access/ require PAM_TTY to be set
* (as they otherwise even try to update it!) but cron doesn't actually allocate a TTY for its forked
* off processes.) */
type = "unspecified";
class = "background";
tty = NULL;
} else if (streq_ptr(tty, "ssh")) {
/* ssh has been setting PAM_TTY to "ssh" (for the same reason as cron does this, see above. For further
* details look for "PAM_TTY_KLUDGE" in the openssh sources). */
type = "tty";
class = "user";
tty = NULL; /* This one is particularly sad, as this means that ssh sessions — even though usually
* associated with a pty won't be tracked by their tty in logind. This is because ssh
* does the PAM session registration early for new connections, and registers a pty only
* much later (this is because it doesn't know yet if it needs one at all, as whether to
* register a pty or not is negotiated much later in the protocol). */
} else if (tty)
/* Chop off leading /dev prefix that some clients specify, but others do not. */
tty = skip_dev_prefix(tty);
/* If this fails vtnr will be 0, that's intended */
if (!isempty(cvtnr))
(void) safe_atou32(cvtnr, &vtnr);
if (!isempty(display) && !vtnr) {
if (isempty(seat))
(void) get_seat_from_display(display, &seat, &vtnr);
else if (streq(seat, "seat0"))
(void) get_seat_from_display(display, NULL, &vtnr);
}
if (seat && !streq(seat, "seat0") && vtnr != 0) {
pam_debug_syslog(handle, debug, "Ignoring vtnr %"PRIu32" for %s which is not seat0", vtnr, seat);
vtnr = 0;
}
if (isempty(type))
type = !isempty(display) ? "x11" :
!isempty(tty) ? "tty" : "unspecified";
if (isempty(class))
class = streq(type, "unspecified") ? "background" :
((IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC) &&
streq(type, "tty")) ? "user-early" : "user");
if (incomplete) {
if (streq(class, "user"))
class = "user-incomplete";
else
pam_syslog_pam_error(handle, LOG_WARNING, 0, "PAM session of class '%s' is incomplete, which is not supported, ignoring.", class);
}
remote = !isempty(remote_host) && !is_localhost(remote_host);
r = pam_get_data(handle, "systemd.memory_max", (const void **)&memory_max);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.memory_max data: @PAMERR@");
r = pam_get_data(handle, "systemd.tasks_max", (const void **)&tasks_max);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.tasks_max data: @PAMERR@");
r = pam_get_data(handle, "systemd.cpu_weight", (const void **)&cpu_weight);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.cpu_weight data: @PAMERR@");
r = pam_get_data(handle, "systemd.io_weight", (const void **)&io_weight);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.io_weight data: @PAMERR@");
r = pam_get_data(handle, "systemd.runtime_max_sec", (const void **)&runtime_max_sec);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.runtime_max_sec data: @PAMERR@");
/* Talk to logind over the message bus */ /* Talk to logind over the message bus */
r = pam_acquire_bus_connection(handle, "pam-systemd", debug, &bus, &d); r = pam_acquire_bus_connection(handle, "pam-systemd", debug, &bus, &d);
@ -1095,41 +1061,22 @@ _public_ PAM_EXTERN int pam_sm_open_session(
"Asking logind to create session: " "Asking logind to create session: "
"uid="UID_FMT" pid="PID_FMT" service=%s type=%s class=%s desktop=%s seat=%s vtnr=%"PRIu32" tty=%s display=%s remote=%s remote_user=%s remote_host=%s", "uid="UID_FMT" pid="PID_FMT" service=%s type=%s class=%s desktop=%s seat=%s vtnr=%"PRIu32" tty=%s display=%s remote=%s remote_user=%s remote_host=%s",
ur->uid, getpid_cached(), ur->uid, getpid_cached(),
strempty(service), strempty(c->service),
type, class, strempty(desktop), c->type, c->class, strempty(c->desktop),
strempty(seat), vtnr, strempty(tty), strempty(display), strempty(c->seat), c->vtnr, strempty(c->tty), strempty(c->display),
yes_no(remote), strempty(remote_user), strempty(remote_host)); yes_no(c->remote), strempty(c->remote_user), strempty(c->remote_host));
pam_debug_syslog(handle, debug, pam_debug_syslog(handle, debug,
"Session limits: " "Session limits: "
"memory_max=%s tasks_max=%s cpu_weight=%s io_weight=%s runtime_max_sec=%s", "memory_max=%s tasks_max=%s cpu_weight=%s io_weight=%s runtime_max_sec=%s",
strna(memory_max), strna(tasks_max), strna(cpu_weight), strna(io_weight), strna(runtime_max_sec)); strna(c->memory_max), strna(c->tasks_max), strna(c->cpu_weight), strna(c->io_weight), strna(c->runtime_max_sec));
const SessionContext context = { r = create_session_message(
.uid = ur->uid, bus,
.pid = 0, handle,
.service = service, ur,
.type = type, c,
.class = class, /* avoid_pidfd = */ false,
.desktop = desktop, &m);
.seat = seat,
.vtnr = vtnr,
.tty = tty,
.display = display,
.remote = remote,
.remote_user = remote_user,
.remote_host = remote_host,
.memory_max = memory_max,
.tasks_max = tasks_max,
.cpu_weight = cpu_weight,
.io_weight = io_weight,
.runtime_max_sec = runtime_max_sec,
};
r = create_session_message(bus,
handle,
&context,
/* avoid_pidfd = */ false,
&m);
if (r < 0) if (r < 0)
return pam_bus_log_create_error(handle, r); return pam_bus_log_create_error(handle, r);
@ -1142,7 +1089,8 @@ _public_ PAM_EXTERN int pam_sm_open_session(
m = sd_bus_message_unref(m); m = sd_bus_message_unref(m);
r = create_session_message(bus, r = create_session_message(bus,
handle, handle,
&context, ur,
c,
/* avoid_pidfd = */ true, /* avoid_pidfd = */ true,
&m); &m);
if (r < 0) if (r < 0)
@ -1155,7 +1103,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
/* We are already in a session, don't do anything */ /* We are already in a session, don't do anything */
pam_debug_syslog(handle, debug, pam_debug_syslog(handle, debug,
"Not creating session: %s", bus_error_message(&error, r)); "Not creating session: %s", bus_error_message(&error, r));
goto success; goto skip;
} }
pam_syslog(handle, LOG_ERR, pam_syslog(handle, LOG_ERR,
@ -1163,23 +1111,27 @@ _public_ PAM_EXTERN int pam_sm_open_session(
return PAM_SESSION_ERR; return PAM_SESSION_ERR;
} }
r = sd_bus_message_read(reply, const char *id, *object_path, *runtime_path, *real_seat;
"soshusub", int session_fd = -EBADF, existing;
&id, uint32_t original_uid, real_vtnr;
&object_path, r = sd_bus_message_read(
&runtime_path, reply,
&session_fd, "soshusub",
&original_uid, &id,
&seat, &object_path,
&vtnr, &runtime_path,
&existing); &session_fd,
&original_uid,
&real_seat,
&real_vtnr,
&existing);
if (r < 0) if (r < 0)
return pam_bus_log_parse_error(handle, r); return pam_bus_log_parse_error(handle, r);
pam_debug_syslog(handle, debug, pam_debug_syslog(handle, debug,
"Reply from logind: " "Reply from logind: "
"id=%s object_path=%s runtime_path=%s session_fd=%d seat=%s vtnr=%u original_uid=%u", "id=%s object_path=%s runtime_path=%s session_fd=%d seat=%s vtnr=%u original_uid=%u",
id, object_path, runtime_path, session_fd, seat, vtnr, original_uid); id, object_path, runtime_path, session_fd, real_seat, real_vtnr, original_uid);
/* Please update manager_default_environment() in core/manager.c accordingly if more session envvars /* Please update manager_default_environment() in core/manager.c accordingly if more session envvars
* shall be added. */ * shall be added. */
@ -1202,38 +1154,25 @@ _public_ PAM_EXTERN int pam_sm_open_session(
* somewhere else (for example PAM module parameters). Let's now update the environment variables, so that this * somewhere else (for example PAM module parameters). Let's now update the environment variables, so that this
* data is inherited into the session processes, and programs can rely on them to be initialized. */ * data is inherited into the session processes, and programs can rely on them to be initialized. */
r = update_environment(handle, "XDG_SESSION_TYPE", type); r = update_environment(handle, "XDG_SESSION_TYPE", c->type);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
r = update_environment(handle, "XDG_SESSION_CLASS", class); r = update_environment(handle, "XDG_SESSION_CLASS", c->class);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
r = update_environment(handle, "XDG_SESSION_DESKTOP", desktop); r = update_environment(handle, "XDG_SESSION_DESKTOP", c->desktop);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
r = update_environment(handle, "XDG_SEAT", seat); r = update_environment(handle, "XDG_SEAT", real_seat);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
static const char *const propagate[] = { if (real_vtnr > 0) {
"shell.prompt.prefix", "SHELL_PROMPT_PREFIX", char buf[DECIMAL_STR_MAX(real_vtnr)];
"shell.prompt.suffix", "SHELL_PROMPT_SUFFIX", sprintf(buf, "%u", real_vtnr);
"shell.welcome", "SHELL_WELCOME",
NULL
};
STRV_FOREACH_PAIR(k, v, propagate) {
r = propagate_credential_to_environment(handle, *k, *v);
if (r != PAM_SUCCESS)
return r;
}
if (vtnr > 0) {
char buf[DECIMAL_STR_MAX(vtnr)];
sprintf(buf, "%u", vtnr);
r = update_environment(handle, "XDG_VTNR", buf); r = update_environment(handle, "XDG_VTNR", buf);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
@ -1255,9 +1194,115 @@ _public_ PAM_EXTERN int pam_sm_open_session(
TAKE_FD(fd); TAKE_FD(fd);
} }
success: /* Everything worked, hence let's patch in the data we learned. Since 'real_set' points into the
* D-Bus message, let's copy it and return it as a buffer */
char *rs = strdup(real_seat);
if (!rs)
return pam_log_oom(handle);
c->seat = *ret_seat = rs;
c->vtnr = real_vtnr;
return PAM_SUCCESS;
skip:
*ret_seat = NULL;
return PAM_SUCCESS;
}
static int import_shell_credentials(pam_handle_t *handle) {
static const char *const propagate[] = {
"shell.prompt.prefix", "SHELL_PROMPT_PREFIX",
"shell.prompt.suffix", "SHELL_PROMPT_SUFFIX",
"shell.welcome", "SHELL_WELCOME",
NULL
};
int r;
assert(handle);
STRV_FOREACH_PAIR(k, v, propagate) {
r = propagate_credential_to_environment(handle, *k, *v);
if (r != PAM_SUCCESS)
return r;
}
return PAM_SUCCESS;
}
_public_ PAM_EXTERN int pam_sm_open_session(
pam_handle_t *handle,
int flags,
int argc, const char **argv) {
int r;
assert(handle);
pam_log_setup();
uint64_t default_capability_bounding_set = UINT64_MAX, default_capability_ambient_set = UINT64_MAX;
const char *class_pam = NULL, *type_pam = NULL, *desktop_pam = NULL;
bool debug = false;
if (parse_argv(handle,
argc, argv,
&class_pam,
&type_pam,
&desktop_pam,
&debug,
&default_capability_bounding_set,
&default_capability_ambient_set) < 0)
return PAM_SESSION_ERR;
pam_debug_syslog(handle, debug, "pam-systemd initializing");
_cleanup_(user_record_unrefp) UserRecord *ur = NULL;
r = acquire_user_record(handle, &ur);
if (r != PAM_SUCCESS)
return r;
SessionContext c = {};
r = pam_get_item_many(
handle,
PAM_SERVICE, &c.service,
PAM_XDISPLAY, &c.display,
PAM_TTY, &c.tty,
PAM_RUSER, &c.remote_user,
PAM_RHOST, &c.remote_host);
if (r != PAM_SUCCESS)
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM items: @PAMERR@");
c.seat = getenv_harder(handle, "XDG_SEAT", NULL);
c.vtnr = getenv_harder_uint32(handle, "XDG_VTNR", 0);
c.type = getenv_harder(handle, "XDG_SESSION_TYPE", type_pam);
c.class = getenv_harder(handle, "XDG_SESSION_CLASS", class_pam);
c.desktop = getenv_harder(handle, "XDG_SESSION_DESKTOP", desktop_pam);
c.incomplete = getenv_harder_bool(handle, "XDG_SESSION_INCOMPLETE", false);
r = pam_get_data_many(
handle,
"systemd.memory_max", &c.memory_max,
"systemd.tasks_max", &c.tasks_max,
"systemd.cpu_weight", &c.cpu_weight,
"systemd.io_weight", &c.io_weight,
"systemd.runtime_max_sec", &c.runtime_max_sec);
if (r != PAM_SUCCESS)
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM data: @PAMERR@");
session_context_mangle(handle, &c, ur, debug);
_cleanup_free_ char *seat_buffer = NULL;
r = register_session(handle, &c, ur, debug, &seat_buffer);
if (r != PAM_SUCCESS)
return r;
r = import_shell_credentials(handle);
if (r != PAM_SUCCESS)
return r;
if (default_capability_ambient_set == UINT64_MAX) if (default_capability_ambient_set == UINT64_MAX)
default_capability_ambient_set = pick_default_capability_ambient_set(ur, service, seat); default_capability_ambient_set = pick_default_capability_ambient_set(ur, c.service, c.seat);
return apply_user_record_settings(handle, ur, debug, default_capability_bounding_set, default_capability_ambient_set); return apply_user_record_settings(handle, ur, debug, default_capability_bounding_set, default_capability_ambient_set);
} }

View File

@ -1443,6 +1443,7 @@ int link_reconfigure_impl(Link *link, LinkReconfigurationFlag flags) {
} }
typedef struct LinkReconfigurationData { typedef struct LinkReconfigurationData {
Manager *manager;
Link *link; Link *link;
LinkReconfigurationFlag flags; LinkReconfigurationFlag flags;
sd_bus_message *message; sd_bus_message *message;
@ -1473,6 +1474,12 @@ static void link_reconfiguration_data_destroy_callback(LinkReconfigurationData *
} }
if (!data->counter || *data->counter <= 0) { if (!data->counter || *data->counter <= 0) {
/* Update the state files before replying the bus method. Otherwise,
* systemd-networkd-wait-online following networkctl reload/reconfigure may read an
* outdated state file and wrongly handle an interface is already in the configured
* state. */
(void) manager_clean_all(data->manager);
r = sd_bus_reply_method_return(data->message, NULL); r = sd_bus_reply_method_return(data->message, NULL);
if (r < 0) if (r < 0)
log_warning_errno(r, "Failed to reply for DBus method, ignoring: %m"); log_warning_errno(r, "Failed to reply for DBus method, ignoring: %m");
@ -1521,6 +1528,7 @@ int link_reconfigure_full(Link *link, LinkReconfigurationFlag flags, sd_bus_mess
} }
*data = (LinkReconfigurationData) { *data = (LinkReconfigurationData) {
.manager = link->manager,
.link = link_ref(link), .link = link_ref(link),
.flags = flags, .flags = flags,
.message = sd_bus_message_ref(message), /* message may be NULL, but _ref() works fine. */ .message = sd_bus_message_ref(message), /* message may be NULL, but _ref() works fine. */

View File

@ -2297,7 +2297,8 @@ static int start_transient_scope(sd_bus *bus) {
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
r = get_user_creds(&arg_exec_user, &uid, &gid, &home, &shell, USER_CREDS_CLEAN|USER_CREDS_PREFER_NSS); r = get_user_creds(&arg_exec_user, &uid, &gid, &home, &shell,
USER_CREDS_CLEAN|USER_CREDS_SUPPRESS_PLACEHOLDER|USER_CREDS_PREFER_NSS);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to resolve user %s: %m", arg_exec_user); return log_error_errno(r, "Failed to resolve user %s: %m", arg_exec_user);

View File

@ -46,13 +46,17 @@ static bool argv_has_at(pid_t pid) {
return c == '@'; return c == '@';
} }
static bool is_survivor_cgroup(const PidRef *pid) { static bool is_in_survivor_cgroup(const PidRef *pid) {
_cleanup_free_ char *cgroup_path = NULL; _cleanup_free_ char *cgroup_path = NULL;
int r; int r;
assert(pidref_is_set(pid)); assert(pidref_is_set(pid));
r = cg_pidref_get_path(/* root= */ NULL, pid, &cgroup_path); r = cg_pidref_get_path(/* root= */ NULL, pid, &cgroup_path);
if (r == -EUNATCH) {
log_warning_errno(r, "Process " PID_FMT " appears to originate in foreign namespace, ignoring.", pid->pid);
return true;
}
if (r < 0) { if (r < 0) {
log_warning_errno(r, "Failed to get cgroup path of process " PID_FMT ", ignoring: %m", pid->pid); log_warning_errno(r, "Failed to get cgroup path of process " PID_FMT ", ignoring: %m", pid->pid);
return false; return false;
@ -86,7 +90,7 @@ static bool ignore_proc(const PidRef *pid, bool warn_rootfs) {
return true; /* also ignore processes where we can't determine this */ return true; /* also ignore processes where we can't determine this */
/* Ignore processes that are part of a cgroup marked with the user.survive_final_kill_signal xattr */ /* Ignore processes that are part of a cgroup marked with the user.survive_final_kill_signal xattr */
if (is_survivor_cgroup(pid)) if (is_in_survivor_cgroup(pid))
return true; return true;
r = pidref_get_uid(pid, &uid); r = pidref_get_uid(pid, &uid);

View File

@ -253,17 +253,17 @@ int pam_get_item_many_internal(pam_handle_t *handle, ...) {
va_list ap; va_list ap;
int r; int r;
assert(handle);
va_start(ap, handle); va_start(ap, handle);
for (;;) { for (;;) {
int item_type = va_arg(ap, int); int item_type = va_arg(ap, int);
if (item_type <= 0) { if (item_type <= 0) {
r = PAM_SUCCESS; r = PAM_SUCCESS;
break; break;
} }
const void **value = ASSERT_PTR(va_arg(ap, const void **)); const void **value = ASSERT_PTR(va_arg(ap, const void **));
r = pam_get_item(handle, item_type, value); r = pam_get_item(handle, item_type, value);
if (!IN_SET(r, PAM_BAD_ITEM, PAM_SUCCESS)) if (!IN_SET(r, PAM_BAD_ITEM, PAM_SUCCESS))
break; break;
@ -273,6 +273,30 @@ int pam_get_item_many_internal(pam_handle_t *handle, ...) {
return r; return r;
} }
int pam_get_data_many_internal(pam_handle_t *handle, ...) {
va_list ap;
int r;
assert(handle);
va_start(ap, handle);
for (;;) {
const char *data_name = va_arg(ap, const char *);
if (!data_name) {
r = PAM_SUCCESS;
break;
}
const void **value = ASSERT_PTR(va_arg(ap, const void **));
r = pam_get_data(handle, data_name, value);
if (!IN_SET(r, PAM_NO_MODULE_DATA, PAM_SUCCESS))
break;
}
va_end(ap);
return r;
}
int pam_prompt_graceful(pam_handle_t *handle, int style, char **ret_response, const char *fmt, ...) { int pam_prompt_graceful(pam_handle_t *handle, int style, char **ret_response, const char *fmt, ...) {
va_list args; va_list args;
int r; int r;

View File

@ -44,7 +44,9 @@ int pam_get_bus_data(pam_handle_t *handle, const char *module_name, PamBusData *
void pam_cleanup_free(pam_handle_t *handle, void *data, int error_status); void pam_cleanup_free(pam_handle_t *handle, void *data, int error_status);
int pam_get_item_many_internal(pam_handle_t *handle, ...); int pam_get_item_many_internal(pam_handle_t *handle, ...);
#define pam_get_item_many(handle, ...) pam_get_item_many_internal(handle, __VA_ARGS__, -1) #define pam_get_item_many(handle, ...) pam_get_item_many_internal(handle, __VA_ARGS__, -1)
int pam_get_data_many_internal(pam_handle_t *handle, ...);
#define pam_get_data_many(handle, ...) pam_get_data_many_internal(handle, __VA_ARGS__, NULL)
int pam_prompt_graceful(pam_handle_t *handle, int style, char **ret_response, const char *fmt, ...) _printf_(4,5); int pam_prompt_graceful(pam_handle_t *handle, int style, char **ret_response, const char *fmt, ...) _printf_(4,5);

View File

@ -7,24 +7,26 @@ TEST(audit_loginuid_from_pid) {
_cleanup_(pidref_done) PidRef self = PIDREF_NULL, pid1 = PIDREF_NULL; _cleanup_(pidref_done) PidRef self = PIDREF_NULL, pid1 = PIDREF_NULL;
int r; int r;
assert_se(pidref_set_self(&self) >= 0); ASSERT_OK(pidref_set_self(&self));
assert_se(pidref_set_pid(&pid1, 1) >= 0); ASSERT_OK(pidref_set_pid(&pid1, 1));
uid_t uid; uid_t uid;
r = audit_loginuid_from_pid(&self, &uid); r = audit_loginuid_from_pid(&self, &uid);
assert_se(r >= 0 || r == -ENODATA); if (r != -ENODATA)
ASSERT_OK(r);
if (r >= 0) if (r >= 0)
log_info("self audit login uid: " UID_FMT, uid); log_info("self audit login uid: " UID_FMT, uid);
assert_se(audit_loginuid_from_pid(&pid1, &uid) == -ENODATA); ASSERT_ERROR(audit_loginuid_from_pid(&pid1, &uid), ENODATA);
uint32_t sessionid; uint32_t sessionid;
r = audit_session_from_pid(&self, &sessionid); r = audit_session_from_pid(&self, &sessionid);
assert_se(r >= 0 || r == -ENODATA); if (r != -ENODATA)
ASSERT_OK(r);
if (r >= 0) if (r >= 0)
log_info("self audit session id: %" PRIu32, sessionid); log_info("self audit session id: %" PRIu32, sessionid);
assert_se(audit_session_from_pid(&pid1, &sessionid) == -ENODATA); ASSERT_ERROR(audit_session_from_pid(&pid1, &sessionid), ENODATA);
} }
static int intro(void) { static int intro(void) {

View File

@ -6406,11 +6406,11 @@ class NetworkdRATests(unittest.TestCase, Utilities):
for i in [100, 200, 300, 512, 1024, 2048]: for i in [100, 200, 300, 512, 1024, 2048]:
if i not in [metric_1, metric_2]: if i not in [metric_1, metric_2]:
self.assertNotIn(f'{i}', output) self.assertNotIn(f'metric {i} ', output)
for i in ['low', 'medium', 'high']: for i in ['low', 'medium', 'high']:
if i not in [preference_1, preference_2]: if i not in [preference_1, preference_2]:
self.assertNotIn(f'{i}', output) self.assertNotIn(f'pref {i}', output)
def test_router_preference(self): def test_router_preference(self):
copy_network_unit('25-veth-client.netdev', copy_network_unit('25-veth-client.netdev',

View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
# shellcheck source=test/units/util.sh
. "$(dirname "$0")"/util.sh
(! systemd-run --wait -p DynamicUser=yes \
-p EnvironmentFile=-/usr/lib/systemd/systemd-asan-env \
-p WorkingDirectory='~' true)
assert_eq "$(systemd-run --pipe --uid=root -p WorkingDirectory='~' pwd)" "/root"
assert_eq "$(systemd-run --pipe --uid=nobody -p WorkingDirectory='~' pwd)" "/"
assert_eq "$(systemd-run --pipe --uid=testuser -p WorkingDirectory='~' pwd)" "/home/testuser"
(! systemd-run --wait -p DynamicUser=yes -p User=testuser \
-p EnvironmentFile=-/usr/lib/systemd/systemd-asan-env \
-p WorkingDirectory='~' true)

View File

@ -16,6 +16,7 @@ ConditionDirectoryNotEmpty=|/run/confexts
ConditionDirectoryNotEmpty=|/var/lib/confexts ConditionDirectoryNotEmpty=|/var/lib/confexts
ConditionDirectoryNotEmpty=|/usr/local/lib/confexts ConditionDirectoryNotEmpty=|/usr/local/lib/confexts
ConditionDirectoryNotEmpty=|/usr/lib/confexts ConditionDirectoryNotEmpty=|/usr/lib/confexts
ConditionDirectoryNotEmpty=|/.extra/confext
DefaultDependencies=no DefaultDependencies=no
After=local-fs.target After=local-fs.target