Compare commits
29 Commits
11b4ef7740
...
77409a848a
Author | SHA1 | Date |
---|---|---|
Ronan Pigott | 77409a848a | |
Luca Boccassi | b7eefa1996 | |
Luca Boccassi | 2e5b0412f9 | |
Martin Srebotnjak | 69af4849aa | |
Jiri Grönroos | 18d4e0be89 | |
Dmytro Markevych | 7d7b89a015 | |
Léane GRASSER | 8a92365f79 | |
Yu Watanabe | 2b397d43ab | |
Yu Watanabe | 9ad294efd0 | |
Lennart Poettering | f6793bbcf0 | |
Mike Yuan | f87863a8ff | |
Antonio Alvarez Feijoo | 58c3c2886d | |
Daan De Meyer | dbbe895807 | |
Yu Watanabe | 52b0351a15 | |
Luca Boccassi | fe077a1a58 | |
Xuanjun Wen | a526b9ddfc | |
Mike Yuan | 804dd670d1 | |
Mike Yuan | b718b86e1b | |
Mike Yuan | d911778877 | |
Mike Yuan | eea9d3eb10 | |
Mike Yuan | 579ce77ead | |
Ronan Pigott | d4f1b642c2 | |
Lennart Poettering | 65250fac6a | |
Lennart Poettering | 5d8efe440e | |
Lennart Poettering | 524f0d14e1 | |
Lennart Poettering | ae40305e65 | |
Lennart Poettering | ceb5d4cc73 | |
Lennart Poettering | 68b0318194 | |
Lennart Poettering | 51160b6bca |
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
18
po/fi.po
18
po/fi.po
|
@ -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"
|
||||||
|
|
6
po/fr.po
6
po/fr.po
|
@ -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"
|
||||||
|
|
15
po/sl.po
15
po/sl.po
|
@ -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"
|
||||||
|
|
20
po/uk.po
20
po/uk.po
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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)
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue