]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
logind: add support for booting into the boot menu or a specific boot menu entry
authorLennart Poettering <lennart@poettering.net>
Mon, 22 Oct 2018 18:06:52 +0000 (20:06 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 5 Mar 2019 15:52:46 +0000 (16:52 +0100)
This behaves similar to the "boot into firmware" logic, and also allows
either direct EFI operation (which sd-boot supports and others might
support eventually too) or override through env var.

src/login/logind-dbus.c
src/login/org.freedesktop.login1.conf
src/login/org.freedesktop.login1.policy
units/systemd-logind.service.in

index 262b0290a8337d39194937052301090b5e794c49..7c1e531d2e0c7b940a4180c308a0353a68bd95cb 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "alloc-util.h"
 #include "audit-util.h"
+#include "bootspec.h"
 #include "bus-common-errors.h"
 #include "bus-error.h"
 #include "bus-unit-util.h"
 #include "logind.h"
 #include "missing_capability.h"
 #include "mkdir.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "selinux-util.h"
 #include "sleep-config.h"
 #include "special.h"
+#include "stdio-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "tmpfile-util.h"
@@ -2542,6 +2545,457 @@ static int method_can_reboot_to_firmware_setup(
         return sd_bus_reply_method_return(message, "s", result);
 }
 
+static int property_get_reboot_to_boot_loader_menu(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        uint64_t x = UINT64_MAX;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(userdata);
+
+        r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU");
+        if (r == -ENXIO) {
+                _cleanup_free_ char *v = NULL;
+
+                /* EFI case: returns the current value of LoaderConfigTimeoutOneShot. Three cases are distuingished:
+                 *
+                 *     1. Variable not set, boot into boot loader menu is not enabled (we return UINT64_MAX to the user)
+                 *     2. Variable set to "0", boot into boot loader menu is enabled with no timeout (we return 0 to the user)
+                 *     3. Variable set to numeric value formatted in ASCII, boot into boot loader menu with the specified timeout in seconds
+                 */
+
+                r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderConfigTimeoutOneShot", &v);
+                if (r < 0) {
+                        if (r != -ENOENT)
+                                log_warning_errno(r, "Failed to read LoaderConfigTimeoutOneShot variable: %m");
+                } else {
+                        uint64_t sec;
+
+                        r = safe_atou64(v, &sec);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to parse LoaderConfigTimeoutOneShot value '%s': %m", v);
+                        else if (sec > (USEC_INFINITY / USEC_PER_SEC))
+                                log_warning("LoaderConfigTimeoutOneShot too large, ignoring: %m");
+                        else
+                                x = sec * USEC_PER_SEC; /* return in µs */
+                }
+
+        } else if (r < 0)
+                log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU: %m");
+        else if (r > 0) {
+                _cleanup_free_ char *v = NULL;
+
+                /* Non-EFI case, let's process /run/systemd/reboot-to-boot-loader-menu. */
+
+                r = read_one_line_file("/run/systemd/reboot-to-boot-loader-menu", &v);
+                if (r < 0) {
+                        if (r != -ENOENT)
+                                log_warning_errno(r, "Failed to read /run/systemd/reboot-to-boot-loader-menu: %m");
+                } else {
+                        r = safe_atou64(v, &x);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to parse /run/systemd/reboot-to-boot-loader-menu: %m");
+                }
+        }
+
+        return sd_bus_message_append(reply, "t", x);
+}
+
+static int method_set_reboot_to_boot_loader_menu(
+                sd_bus_message *message,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Manager *m = userdata;
+        bool use_efi;
+        uint64_t x;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read(message, "t", &x);
+        if (r < 0)
+                return r;
+
+        r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU");
+        if (r == -ENXIO) {
+                uint64_t features;
+
+                /* EFI case: let's see if booting into boot loader menu is supported. */
+
+                r = efi_loader_get_features(&features);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to determine whether reboot to boot loader menu is supported: %m");
+                if (r < 0 || !FLAGS_SET(features, EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Boot loader does not support boot into boot loader menu.");
+
+                use_efi = true;
+
+        } else if (r <= 0) {
+                /* non-EFI case: $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU is set to off */
+
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU: %m");
+
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Boot loader does not support boot into boot loader menu.");
+        } else
+                /* non-EFI case: $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU is set to on */
+                use_efi = false;
+
+        r = bus_verify_polkit_async(message,
+                                    CAP_SYS_ADMIN,
+                                    "org.freedesktop.login1.set-reboot-to-boot-loader-menu",
+                                    NULL,
+                                    false,
+                                    UID_INVALID,
+                                    &m->polkit_registry,
+                                    error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+        if (use_efi) {
+                if (x == UINT64_MAX)
+                        r = efi_set_variable(EFI_VENDOR_LOADER, "LoaderConfigTimeoutOneShot", NULL, 0);
+                else {
+                        char buf[DECIMAL_STR_MAX(uint64_t) + 1];
+                        xsprintf(buf, "%" PRIu64, DIV_ROUND_UP(x, USEC_PER_SEC)); /* second granularity */
+
+                        r = efi_set_variable_string(EFI_VENDOR_LOADER, "LoaderConfigTimeoutOneShot", buf);
+                }
+                if (r < 0)
+                        return r;
+        } else {
+                if (x == UINT64_MAX) {
+                        if (unlink("/run/systemd/reboot-to-loader-menu") < 0 && errno != ENOENT)
+                                return -errno;
+                } else {
+                        char buf[DECIMAL_STR_MAX(uint64_t) + 1];
+
+                        xsprintf(buf, "%" PRIu64, x); /* µs granularity */
+
+                        r = write_string_file_atomic_label("/run/systemd/reboot-to-loader-menu", buf);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+static int method_can_reboot_to_boot_loader_menu(
+                sd_bus_message *message,
+                void *userdata,
+                sd_bus_error *error) {
+
+        const char *result = NULL;
+        Manager *m = userdata;
+        bool challenge;
+        int r;
+
+
+        assert(message);
+        assert(m);
+
+        r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU");
+        if (r == -ENXIO) {
+                uint64_t features = 0;
+
+                /* EFI case, let's see if booting into boot loader menu is supported. */
+
+                r = efi_loader_get_features(&features);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to determine whether reboot to boot loader menu is supported: %m");
+                if (r < 0 || !FLAGS_SET(features, EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT))
+                        result = "na";
+
+        } else if (r <= 0) {
+                /* Non-EFI case: let's trust $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU */
+
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU: %m");
+
+                result = "na";
+        }
+
+        if (result)
+                return sd_bus_reply_method_return(message, "s", result);
+
+        r = bus_test_polkit(message,
+                            CAP_SYS_ADMIN,
+                            "org.freedesktop.login1.set-reboot-to-boot-loader-menu",
+                            NULL,
+                            UID_INVALID,
+                            &challenge,
+                            error);
+        if (r < 0)
+                return r;
+
+        if (r > 0)
+                result = "yes";
+        else if (challenge)
+                result = "challenge";
+        else
+                result = "no";
+
+        return sd_bus_reply_method_return(message, "s", result);
+}
+
+static int property_get_reboot_to_boot_loader_entry(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        _cleanup_free_ char *v = NULL;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(userdata);
+
+        r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY");
+        if (r == -ENXIO) {
+                /* EFI case: let's read the LoaderEntryOneShot variable */
+
+                r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryOneShot", &v);
+                if (r < 0) {
+                        if (r != -ENOENT)
+                                log_warning_errno(r, "Failed to read LoaderEntryOneShot variable: %m");
+                } else if (!efi_loader_entry_name_valid(v)) {
+                        log_warning("LoaderEntryOneShot contains invalid entry name '%s', ignoring.", v);
+                        v = mfree(v);
+                }
+        } else if (r < 0)
+                log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY: %m");
+        else if (r > 0) {
+
+                /* Non-EFI case, let's process /run/systemd/reboot-to-boot-loader-entry. */
+
+                r = read_one_line_file("/run/systemd/reboot-to-boot-loader-entry", &v);
+                if (r < 0) {
+                        if (r != -ENOENT)
+                                log_warning_errno(r, "Failed to read /run/systemd/reboot-to-boot-loader-entry: %m");
+                } else if (!efi_loader_entry_name_valid(v)) {
+                        log_warning("/run/systemd/reboot-to-boot-loader-entry is not valid, ignoring.");
+                        v = mfree(v);
+                }
+        }
+
+        return sd_bus_message_append(reply, "s", v);
+}
+
+static int boot_loader_entry_exists(const char *id) {
+        _cleanup_(boot_config_free) BootConfig config = {};
+        int r;
+
+        assert(id);
+
+        r = boot_entries_load_config_auto(NULL, NULL, &config);
+        if (r < 0)
+                return r;
+
+        (void) boot_entries_augment_from_loader(&config, true);
+
+        return boot_config_has_entry(&config, id);
+}
+
+static int method_set_reboot_to_boot_loader_entry(
+                sd_bus_message *message,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Manager *m = userdata;
+        bool use_efi;
+        const char *v;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read(message, "s", &v);
+        if (r < 0)
+                return r;
+
+        if (isempty(v))
+                v = NULL;
+        else if (efi_loader_entry_name_valid(v)) {
+                r = boot_loader_entry_exists(v);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Boot loader entry '%s' is not known.", v);
+        } else
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Boot loader entry name '%s' is not valid, refusing.", v);
+
+        r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY");
+        if (r == -ENXIO) {
+                uint64_t features;
+
+                /* EFI case: let's see if booting into boot loader entry is supported. */
+
+                r = efi_loader_get_features(&features);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to determine whether reboot into boot loader entry is supported: %m");
+                if (r < 0 || !FLAGS_SET(features, EFI_LOADER_FEATURE_ENTRY_ONESHOT))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Loader does not support boot into boot loader entry.");
+
+                use_efi = true;
+
+        } else if (r <= 0) {
+                /* non-EFI case: $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY is set to off */
+
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY: %m");
+
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Loader does not support boot into boot loader entry.");
+        } else
+                /* non-EFI case: $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY is set to on */
+                use_efi = false;
+
+        r = bus_verify_polkit_async(message,
+                                    CAP_SYS_ADMIN,
+                                    "org.freedesktop.login1.set-reboot-to-boot-loader-entry",
+                                    NULL,
+                                    false,
+                                    UID_INVALID,
+                                    &m->polkit_registry,
+                                    error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+        if (use_efi) {
+                if (isempty(v))
+                        /* Delete item */
+                        r = efi_set_variable(EFI_VENDOR_LOADER, "LoaderEntryOneShot", NULL, 0);
+                else
+                        r = efi_set_variable_string(EFI_VENDOR_LOADER, "LoaderEntryOneShot", v);
+                if (r < 0)
+                        return r;
+        } else {
+                if (isempty(v)) {
+                        if (unlink("/run/systemd/reboot-to-boot-loader-entry") < 0 && errno != ENOENT)
+                                return -errno;
+                } else {
+                        r = write_string_file_atomic_label("/run/systemd/reboot-boot-to-loader-entry", v);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+static int method_can_reboot_to_boot_loader_entry(
+                sd_bus_message *message,
+                void *userdata,
+                sd_bus_error *error) {
+
+        const char *result = NULL;
+        Manager *m = userdata;
+        bool challenge;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY");
+        if (r == -ENXIO) {
+                uint64_t features = 0;
+
+                /* EFI case, let's see if booting into boot loader entry is supported. */
+
+                r = efi_loader_get_features(&features);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to determine whether reboot to boot loader entry is supported: %m");
+                if (r < 0 || !FLAGS_SET(features, EFI_LOADER_FEATURE_ENTRY_ONESHOT))
+                        result = "na";
+
+        } else if (r <= 0) {
+                /* Non-EFI case: let's trust $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY */
+
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY: %m");
+
+                result = "na";
+        }
+
+        if (result)
+                return sd_bus_reply_method_return(message, "s", result);
+
+        r = bus_test_polkit(message,
+                            CAP_SYS_ADMIN,
+                            "org.freedesktop.login1.set-reboot-to-boot-loader-entry",
+                            NULL,
+                            UID_INVALID,
+                            &challenge,
+                            error);
+        if (r < 0)
+                return r;
+
+        if (r > 0)
+                result = "yes";
+        else if (challenge)
+                result = "challenge";
+        else
+                result = "no";
+
+        return sd_bus_reply_method_return(message, "s", result);
+}
+
+static int property_get_boot_loader_entries(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        _cleanup_(boot_config_free) BootConfig config = {};
+        size_t i;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(userdata);
+
+        r = boot_entries_load_config_auto(NULL, NULL, &config);
+        if (r < 0)
+                return r;
+
+        (void) boot_entries_augment_from_loader(&config, true);
+
+        r = sd_bus_message_open_container(reply, 'a', "s");
+        if (r < 0)
+                return r;
+
+        for (i = 0; i < config.n_entries; i++) {
+                BootEntry *e = config.entries + i;
+
+                r = sd_bus_message_append(reply, "s", e->id);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_bus_message_close_container(reply);
+}
+
 static int method_set_wall_message(
                 sd_bus_message *message,
                 void *userdata,
@@ -2707,6 +3161,9 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RebootToFirmwareSetup", "b", property_get_reboot_to_firmware_setup, 0, 0),
+        SD_BUS_PROPERTY("RebootToBootLoaderMenu", "t", property_get_reboot_to_boot_loader_menu, 0, 0),
+        SD_BUS_PROPERTY("RebootToBootLoaderEntry", "s", property_get_reboot_to_boot_loader_entry, 0, 0),
+        SD_BUS_PROPERTY("BootLoaderEntries", "as", property_get_boot_loader_entries, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -2781,6 +3238,10 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("CanRebootToBootLoaderMenu", NULL, "s", method_can_reboot_to_boot_loader_menu, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetRebootToBootLoaderMenu", "t", NULL, method_set_reboot_to_boot_loader_menu, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("CanRebootToBootLoaderEntry", NULL, "s", method_can_reboot_to_boot_loader_entry, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetRebootToBootLoaderEntry", "s", NULL, method_set_reboot_to_boot_loader_entry, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetWallMessage", "sb", NULL, method_set_wall_message, SD_BUS_VTABLE_UNPRIVILEGED),
 
         SD_BUS_SIGNAL("SessionNew", "so", 0),
index f880f3e2da40257d445786cfb2055c3c461d698d..5677c15b8a963bdb694b227429794a32137f79d1 100644 (file)
                        send_interface="org.freedesktop.login1.Manager"
                        send_member="SetRebootToFirmwareSetup"/>
 
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="CanRebootToBootLoaderMenu"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="SetRebootToBootLoaderMenu"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="CanRebootToBootLoaderEntry"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="SetRebootToBootLoaderEntry"/>
+
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Manager"
                        send_member="SetWallMessage"/>
index 5ee62ab5b49eda6847beafde9f1df616b0aaaeb9..671384d34e88bd8ecc8ee8d39404772ab15ef9ce 100644 (file)
         </action>
 
         <action id="org.freedesktop.login1.set-reboot-to-firmware-setup">
-                <description gettext-domain="systemd">Allow indication to the firmware to boot to setup interface</description>
+                <description gettext-domain="systemd">Indicate to the firmware to boot to setup interface</description>
                 <message gettext-domain="systemd">Authentication is required to indicate to the firmware to boot to setup interface.</message>
                 <defaults>
                         <allow_any>auth_admin_keep</allow_any>
                 <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.reboot</annotate>
         </action>
 
+        <action id="org.freedesktop.login1.set-reboot-to-boot-loader-menu">
+                <description gettext-domain="systemd">Indicate to the boot loader to boot to the boot loader menu</description>
+                <message gettext-domain="systemd">Authentication is required to indicate to the boot loader to boot to the boot loader menu.</message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>yes</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.reboot</annotate>
+        </action>
+
+        <action id="org.freedesktop.login1.set-reboot-to-boot-loader-entry">
+                <description gettext-domain="systemd">Indicate to the boot loader to boot a specific entry</description>
+                <message gettext-domain="systemd">Authentication is required to indicate to the boot loader to boot into a specific boot loader entry.</message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>yes</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.reboot</annotate>
+        </action>
+
         <action id="org.freedesktop.login1.set-wall-message">
                 <description gettext-domain="systemd">Set a wall message</description>
                 <message gettext-domain="systemd">Authentication is required to set a wall message</message>
index fb6fda49077742d746fb106c194bc88da884a59c..a864f66c688326286a8bcca6a32e9665536ccf37 100644 (file)
@@ -21,7 +21,7 @@ After=dbus.socket
 
 [Service]
 BusName=org.freedesktop.login1
-CapabilityBoundingSet=CAP_SYS_ADMIN CAP_MAC_ADMIN CAP_AUDIT_CONTROL CAP_CHOWN CAP_KILL CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_FOWNER CAP_SYS_TTY_CONFIG
+CapabilityBoundingSet=CAP_SYS_ADMIN CAP_MAC_ADMIN CAP_AUDIT_CONTROL CAP_CHOWN CAP_KILL CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_FOWNER CAP_SYS_TTY_CONFIG CAP_LINUX_IMMUTABLE
 ExecStart=@rootlibexecdir@/systemd-logind
 FileDescriptorStoreMax=512
 IPAddressDeny=any