diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in index 1a5f0aec89c..200c98eabe9 100644 --- a/catalog/systemd.catalog.in +++ b/catalog/systemd.catalog.in @@ -119,6 +119,16 @@ Documentation: sd-login(3) A seat @SEAT_ID@ has been removed and is no longer available. +-- b2bcbaf5edf948e093ce50bbea0e81ec +Subject: The Secure Attention Key (SAK) was pressed on @SEAT_ID@ +Defined-By: systemd +Support: %SUPPORT_URL% +Documentation: man:systemd-logind.service(8) + +The Secure Attention Key (SAK), Ctrl+Alt+Shift+Esc, was pressed on @SEAT_ID@. + +Pressing the SAK indicates an explicit request by the user for the system to display a secure login dialog or greeter. + -- c7a787079b354eaaa9e77b371893cd27 Subject: Time change Defined-By: systemd diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 9ec6cb1c400..66240b58fe8 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -224,13 +224,14 @@ HandleLidSwitch= HandleLidSwitchExternalPower= HandleLidSwitchDocked= + HandleSecureAttentionKey= Controls how logind shall handle the system power, reboot and sleep keys and the lid switch to trigger actions such as system power-off, reboot or suspend. Can be one of ignore, poweroff, reboot, halt, kexec, suspend, hibernate, hybrid-sleep, suspend-then-hibernate, sleep, lock, and - factory-reset. If ignore, systemd-logind + factory-reset, secure-attention-key. If ignore, systemd-logind will never handle these keys. If lock, all running sessions will be screen-locked; otherwise, the specified action will be taken in the respective event. Only input devices with the power-switch udev tag will be watched for key/lid switch @@ -251,7 +252,8 @@ system is inserted in a docking station, or if more than one display is connected, the action specified by HandleLidSwitchDocked= occurs; if the system is on external power the action (if any) specified by HandleLidSwitchExternalPower= occurs; otherwise the - HandleLidSwitch= action occurs. + HandleLidSwitch= action occurs. + HandleSecureAttentionKey= defaults to secure-attention-key A different application may disable logind's handling of system power and sleep keys and the lid switch by taking a low-level inhibitor lock @@ -262,7 +264,7 @@ to take over suspend and hibernation handling, and to use their own configuration mechanisms. If a low-level inhibitor lock is taken, logind will not take any action when that key or switch is triggered and the Handle*= - settings are irrelevant. + settings are irrelevant, except for HandleSecureAttentionKey=, which is always handled since its addition in v257. diff --git a/man/org.freedesktop.login1.xml b/man/org.freedesktop.login1.xml index ad9b00e8eb0..cba371ca9e2 100644 --- a/man/org.freedesktop.login1.xml +++ b/man/org.freedesktop.login1.xml @@ -169,6 +169,8 @@ node /org/freedesktop/login1 { SetWallMessage(in s wall_message, in b enable); signals: + SecureAttentionKey(s seat_id, + o object_path); SessionNew(s session_id, o object_path); SessionRemoved(s session_id, @@ -244,6 +246,8 @@ node /org/freedesktop/login1 { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s HandleLidSwitchDocked = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s HandleSecureAttentionKey = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly t HoldoffTimeoutUSec = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s IdleAction = '...'; @@ -296,6 +300,8 @@ node /org/freedesktop/login1 { + + @@ -430,6 +436,8 @@ node /org/freedesktop/login1 { + + @@ -508,6 +516,8 @@ node /org/freedesktop/login1 { + + @@ -733,6 +743,10 @@ node /org/freedesktop/login1 { Whenever the inhibition state or idle hint changes, PropertyChanged signals are sent out to which clients can subscribe. + The SecureAttentionKey() signal is sent when the user presses Ctrl+Alt+Shift+Esc to + request the login manager to display the greeter, for instance in the case of a deadlocked compositor. + + The SessionNew(), SessionRemoved(), UserNew(), UserRemoved(), SeatNew(), and SeatRemoved() signals are sent each time a session is created or removed, a user @@ -1590,6 +1604,8 @@ node /org/freedesktop/login1/session/1 { SleepOperation, DesignatedMaintenanceTime, and ListSessionsEx() were added in version 256. + HandleSecureAttentionKey, and + SecureAttentionKey() were added in version 257. Session Objects diff --git a/src/login/logind-action.c b/src/login/logind-action.c index 9325d91549d..686ba358f7e 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -12,6 +12,7 @@ #include "format-util.h" #include "logind-action.h" #include "logind-dbus.h" +#include "logind-seat-dbus.h" #include "logind-session-dbus.h" #include "process-util.h" #include "special.h" @@ -299,12 +300,55 @@ static int handle_action_sleep_execute( return handle_action_execute(m, handle, ignore_inhibited, is_edge); } +static int manager_handle_action_secure_attention_key( + Manager *m, + bool is_edge, + const char *seat) { + + int r; + Seat *o; + _cleanup_free_ char *p = NULL; + + assert(m); + + if (!is_edge) + return 0; + + if (!seat) + return 0; + + o = hashmap_get(m->seats, seat); + if (!o) + return 0; + + p = seat_bus_path(o); + if (!p) + return log_oom(); + + log_struct(LOG_INFO, + LOG_MESSAGE("Secure Attention Key sequence pressed on seat %s", seat), + "MESSAGE_ID=" SD_MESSAGE_SECURE_ATTENTION_KEY_PRESS_STR, + "SEAT_ID=%s", seat); + + r = sd_bus_emit_signal( + m->bus, + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "SecureAttentionKey", + "so", seat, p); + if (r < 0) + log_warning_errno(r, "Failed to emit SecureAttentionKey signal, ignoring: %m"); + + return 0; +} + int manager_handle_action( Manager *m, InhibitWhat inhibit_key, HandleAction handle, bool ignore_inhibited, - bool is_edge) { + bool is_edge, + const char *action_seat) { assert(m); assert(handle_action_valid(handle)); @@ -336,7 +380,7 @@ int manager_handle_action( } } - /* Locking is handled differently from the rest. */ + /* Locking and greeter activation is handled differently from the rest. */ if (handle == HANDLE_LOCK) { if (!is_edge) return 0; @@ -346,6 +390,9 @@ int manager_handle_action( return 1; } + if (handle == HANDLE_SECURE_ATTENTION_KEY) + return manager_handle_action_secure_attention_key(m, is_edge, action_seat); + if (HANDLE_ACTION_IS_SLEEP(handle)) return handle_action_sleep_execute(m, handle, ignore_inhibited, is_edge); @@ -366,6 +413,7 @@ static const char* const handle_action_verb_table[_HANDLE_ACTION_MAX] = { [HANDLE_SLEEP] = "sleep", [HANDLE_FACTORY_RESET] = "perform a factory reset", [HANDLE_LOCK] = "be locked", + [HANDLE_SECURE_ATTENTION_KEY] = "handle the secure attention key", }; DEFINE_STRING_TABLE_LOOKUP_TO_STRING(handle_action_verb, HandleAction); @@ -386,6 +434,7 @@ static const char* const handle_action_table[_HANDLE_ACTION_MAX] = { [HANDLE_SLEEP] = "sleep", [HANDLE_FACTORY_RESET] = "factory-reset", [HANDLE_LOCK] = "lock", + [HANDLE_SECURE_ATTENTION_KEY] = "secure-attention-key", }; DEFINE_STRING_TABLE_LOOKUP(handle_action, HandleAction); diff --git a/src/login/logind-action.h b/src/login/logind-action.h index c78c18c5aad..800f4e83099 100644 --- a/src/login/logind-action.h +++ b/src/login/logind-action.h @@ -22,6 +22,7 @@ typedef enum HandleAction { HANDLE_SLEEP, /* A "high-level" action that automatically choose an appropriate low-level sleep action */ _HANDLE_ACTION_SLEEP_LAST = HANDLE_SLEEP, + HANDLE_SECURE_ATTENTION_KEY, HANDLE_LOCK, HANDLE_FACTORY_RESET, @@ -77,7 +78,8 @@ int manager_handle_action( InhibitWhat inhibit_key, HandleAction handle, bool ignore_inhibited, - bool is_edge); + bool is_edge, + const char *action_seat); const char* handle_action_verb_to_string(HandleAction h) _const_; diff --git a/src/login/logind-button.c b/src/login/logind-button.c index 14835aedc15..f980ea5eced 100644 --- a/src/login/logind-button.c +++ b/src/login/logind-button.c @@ -15,7 +15,36 @@ #include "missing_input.h" #include "string-util.h" -#define CONST_MAX5(a, b, c, d, e) CONST_MAX(CONST_MAX(a, b), CONST_MAX(CONST_MAX(c, d), e)) +/* KEY_RESTART is the highest value key in keys_interested. */ +#define _KEY_MAX_INTERESTED KEY_RESTART + +/* Adding more values here may require _KEY_MAX_INTERESTED to be updated, this array must be sorted by key value. */ +static const int keys_interested[] = { + KEY_ESC, + KEY_LEFTCTRL, + KEY_LEFTSHIFT, + KEY_RIGHTSHIFT, + KEY_LEFTALT, + KEY_RIGHTCTRL, + KEY_RIGHTALT, + KEY_POWER, + KEY_SLEEP, + KEY_SUSPEND, + KEY_POWER2, + KEY_RESTART, +}; + +static const struct { + int keycode; + ButtonModifierMask modifier_mask; +} keycode_modifier_table[] = { + { KEY_LEFTSHIFT, BUTTON_MODIFIER_LEFT_SHIFT }, + { KEY_RIGHTSHIFT, BUTTON_MODIFIER_RIGHT_SHIFT }, + { KEY_LEFTCTRL, BUTTON_MODIFIER_LEFT_CTRL }, + { KEY_RIGHTCTRL, BUTTON_MODIFIER_RIGHT_CTRL }, + { KEY_LEFTALT, BUTTON_MODIFIER_LEFT_ALT }, + { KEY_RIGHTALT, BUTTON_MODIFIER_RIGHT_ALT }, +}; #define ULONG_BITS (sizeof(unsigned long)*8) @@ -48,6 +77,8 @@ Button* button_new(Manager *m, const char *name) { return mfree(b); } + b->button_modifier_mask = BUTTON_MODIFIER_NONE; + b->manager = m; b->fd = -EBADF; @@ -77,7 +108,18 @@ int button_set_seat(Button *b, const char *sn) { return free_and_strdup(&b->seat, sn); } -static void button_lid_switch_handle_action(Manager *manager, bool is_edge) { +static ButtonModifierMask button_get_keycode_modifier_mask(int keycode) { + + assert(keycode > 0); + + FOREACH_ELEMENT(i, keycode_modifier_table) + if (i->keycode == keycode) + return i->modifier_mask; + + return BUTTON_MODIFIER_NONE; +} + +static void button_lid_switch_handle_action(Manager *manager, bool is_edge, const char* seat) { HandleAction handle_action; assert(manager); @@ -91,7 +133,7 @@ static void button_lid_switch_handle_action(Manager *manager, bool is_edge) { else handle_action = manager->handle_lid_switch; - manager_handle_action(manager, INHIBIT_HANDLE_LID_SWITCH, handle_action, manager->lid_switch_ignore_inhibited, is_edge); + manager_handle_action(manager, INHIBIT_HANDLE_LID_SWITCH, handle_action, manager->lid_switch_ignore_inhibited, is_edge, seat); } static int button_recheck(sd_event_source *e, void *userdata) { @@ -99,7 +141,7 @@ static int button_recheck(sd_event_source *e, void *userdata) { assert(b->lid_closed); - button_lid_switch_handle_action(b->manager, false); + button_lid_switch_handle_action(b->manager, /* is_edge= */ false, b->seat); return 1; } @@ -120,7 +162,8 @@ static int button_install_check_event_source(Button *b) { } static int long_press_of_power_key_handler(sd_event_source *e, uint64_t usec, void *userdata) { - Manager *m = ASSERT_PTR(userdata); + Button *b = ASSERT_PTR(userdata); + Manager *m = ASSERT_PTR(b->manager); assert(e); @@ -130,12 +173,13 @@ static int long_press_of_power_key_handler(sd_event_source *e, uint64_t usec, vo LOG_MESSAGE("Power key pressed long."), "MESSAGE_ID=" SD_MESSAGE_POWER_KEY_LONG_PRESS_STR); - manager_handle_action(m, INHIBIT_HANDLE_POWER_KEY, m->handle_power_key_long_press, m->power_key_ignore_inhibited, true); + manager_handle_action(m, INHIBIT_HANDLE_POWER_KEY, m->handle_power_key_long_press, m->power_key_ignore_inhibited, /* is_edge= */ true, b->seat); return 0; } static int long_press_of_reboot_key_handler(sd_event_source *e, uint64_t usec, void *userdata) { - Manager *m = ASSERT_PTR(userdata); + Button *b = ASSERT_PTR(userdata); + Manager *m = ASSERT_PTR(b->manager); assert(e); @@ -145,12 +189,13 @@ static int long_press_of_reboot_key_handler(sd_event_source *e, uint64_t usec, v LOG_MESSAGE("Reboot key pressed long."), "MESSAGE_ID=" SD_MESSAGE_REBOOT_KEY_LONG_PRESS_STR); - manager_handle_action(m, INHIBIT_HANDLE_REBOOT_KEY, m->handle_reboot_key_long_press, m->reboot_key_ignore_inhibited, true); + manager_handle_action(m, INHIBIT_HANDLE_REBOOT_KEY, m->handle_reboot_key_long_press, m->reboot_key_ignore_inhibited, /* is_edge= */ true, b->seat); return 0; } static int long_press_of_suspend_key_handler(sd_event_source *e, uint64_t usec, void *userdata) { - Manager *m = ASSERT_PTR(userdata); + Button *b = ASSERT_PTR(userdata); + Manager *m = ASSERT_PTR(b->manager); assert(e); @@ -160,12 +205,13 @@ static int long_press_of_suspend_key_handler(sd_event_source *e, uint64_t usec, LOG_MESSAGE("Suspend key pressed long."), "MESSAGE_ID=" SD_MESSAGE_SUSPEND_KEY_LONG_PRESS_STR); - manager_handle_action(m, INHIBIT_HANDLE_SUSPEND_KEY, m->handle_suspend_key_long_press, m->suspend_key_ignore_inhibited, true); + manager_handle_action(m, INHIBIT_HANDLE_SUSPEND_KEY, m->handle_suspend_key_long_press, m->suspend_key_ignore_inhibited, /* is_edge= */ true, b->seat); return 0; } static int long_press_of_hibernate_key_handler(sd_event_source *e, uint64_t usec, void *userdata) { - Manager *m = ASSERT_PTR(userdata); + Button *b = ASSERT_PTR(userdata); + Manager *m = ASSERT_PTR(b->manager); assert(e); @@ -175,15 +221,17 @@ static int long_press_of_hibernate_key_handler(sd_event_source *e, uint64_t usec LOG_MESSAGE("Hibernate key pressed long."), "MESSAGE_ID=" SD_MESSAGE_HIBERNATE_KEY_LONG_PRESS_STR); - manager_handle_action(m, INHIBIT_HANDLE_HIBERNATE_KEY, m->handle_hibernate_key_long_press, m->hibernate_key_ignore_inhibited, true); + manager_handle_action(m, INHIBIT_HANDLE_HIBERNATE_KEY, m->handle_hibernate_key_long_press, m->hibernate_key_ignore_inhibited, /* is_edge= */ true, b->seat); return 0; } -static void start_long_press(Manager *m, sd_event_source **e, sd_event_time_handler_t callback) { +static void start_long_press(Button *b, sd_event_source **e, sd_event_time_handler_t callback) { + Manager *m; int r; - assert(m); + assert(b); assert(e); + m = ASSERT_PTR(b->manager); if (*e) return; @@ -193,7 +241,7 @@ static void start_long_press(Manager *m, sd_event_source **e, sd_event_time_hand e, CLOCK_MONOTONIC, LONG_PRESS_DURATION, 0, - callback, m); + callback, b); if (r < 0) log_warning_errno(r, "Failed to add long press timer event, ignoring: %m"); } @@ -220,12 +268,12 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u case KEY_POWER2: if (b->manager->handle_power_key_long_press != HANDLE_IGNORE && b->manager->handle_power_key_long_press != b->manager->handle_power_key) { log_debug("Power key pressed. Further action depends on the key press duration."); - start_long_press(b->manager, &b->manager->power_key_long_press_event_source, long_press_of_power_key_handler); + start_long_press(b, &b->manager->power_key_long_press_event_source, long_press_of_power_key_handler); } else { log_struct(LOG_INFO, LOG_MESSAGE("Power key pressed short."), "MESSAGE_ID=" SD_MESSAGE_POWER_KEY_STR); - manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true); + manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, /* is_edge= */ true, b->seat); } break; @@ -237,12 +285,12 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u case KEY_RESTART: if (b->manager->handle_reboot_key_long_press != HANDLE_IGNORE && b->manager->handle_reboot_key_long_press != b->manager->handle_reboot_key) { log_debug("Reboot key pressed. Further action depends on the key press duration."); - start_long_press(b->manager, &b->manager->reboot_key_long_press_event_source, long_press_of_reboot_key_handler); + start_long_press(b, &b->manager->reboot_key_long_press_event_source, long_press_of_reboot_key_handler); } else { log_struct(LOG_INFO, LOG_MESSAGE("Reboot key pressed short."), "MESSAGE_ID=" SD_MESSAGE_REBOOT_KEY_STR); - manager_handle_action(b->manager, INHIBIT_HANDLE_REBOOT_KEY, b->manager->handle_reboot_key, b->manager->reboot_key_ignore_inhibited, true); + manager_handle_action(b->manager, INHIBIT_HANDLE_REBOOT_KEY, b->manager->handle_reboot_key, b->manager->reboot_key_ignore_inhibited, /* is_edge= */ true, b->seat); } break; @@ -255,26 +303,42 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u case KEY_SLEEP: if (b->manager->handle_suspend_key_long_press != HANDLE_IGNORE && b->manager->handle_suspend_key_long_press != b->manager->handle_suspend_key) { log_debug("Suspend key pressed. Further action depends on the key press duration."); - start_long_press(b->manager, &b->manager->suspend_key_long_press_event_source, long_press_of_suspend_key_handler); + start_long_press(b, &b->manager->suspend_key_long_press_event_source, long_press_of_suspend_key_handler); } else { log_struct(LOG_INFO, LOG_MESSAGE("Suspend key pressed short."), "MESSAGE_ID=" SD_MESSAGE_SUSPEND_KEY_STR); - manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true); + manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, /* is_edge= */ true, b->seat); } break; case KEY_SUSPEND: if (b->manager->handle_hibernate_key_long_press != HANDLE_IGNORE && b->manager->handle_hibernate_key_long_press != b->manager->handle_hibernate_key) { log_debug("Hibernate key pressed. Further action depends on the key press duration."); - start_long_press(b->manager, &b->manager->hibernate_key_long_press_event_source, long_press_of_hibernate_key_handler); + start_long_press(b, &b->manager->hibernate_key_long_press_event_source, long_press_of_hibernate_key_handler); } else { log_struct(LOG_INFO, LOG_MESSAGE("Hibernate key pressed short."), "MESSAGE_ID=" SD_MESSAGE_HIBERNATE_KEY_STR); - manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true); + manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, /* is_edge= */ true, b->seat); } break; + + case KEY_ESC: + if (b->manager->handle_secure_attention_key == HANDLE_IGNORE) + break; + if (!BUTTON_MODIFIER_HAS_SHIFT(b->button_modifier_mask) || + !BUTTON_MODIFIER_HAS_CTRL(b->button_modifier_mask) || + !BUTTON_MODIFIER_HAS_ALT(b->button_modifier_mask)) + break; + + log_debug("Secure Attention Key sequence pressed."); + manager_handle_action(b->manager, /* inhibit_key= */ 0, b->manager->handle_secure_attention_key, /* ignore_inhibited= */ true, /* is_edge= */ true, b->seat); + break; + + default: + b->button_modifier_mask |= button_get_keycode_modifier_mask(ev.code); + break; } } else if (ev.type == EV_KEY && ev.value == 0) { @@ -294,7 +358,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u b->manager->power_key_long_press_event_source = sd_event_source_unref(b->manager->power_key_long_press_event_source); - manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true); + manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, /* is_edge= */ true, b->seat); } break; @@ -306,7 +370,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u b->manager->reboot_key_long_press_event_source = sd_event_source_unref(b->manager->reboot_key_long_press_event_source); - manager_handle_action(b->manager, INHIBIT_HANDLE_REBOOT_KEY, b->manager->handle_reboot_key, b->manager->reboot_key_ignore_inhibited, true); + manager_handle_action(b->manager, INHIBIT_HANDLE_REBOOT_KEY, b->manager->handle_reboot_key, b->manager->reboot_key_ignore_inhibited, /* is_edge= */ true, b->seat); } break; @@ -318,7 +382,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u b->manager->suspend_key_long_press_event_source = sd_event_source_unref(b->manager->suspend_key_long_press_event_source); - manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true); + manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, /* is_edge= */ true, b->seat); } break; case KEY_SUSPEND: @@ -329,9 +393,16 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u b->manager->hibernate_key_long_press_event_source = sd_event_source_unref(b->manager->hibernate_key_long_press_event_source); - manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true); + manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, /* is_edge= */ true, b->seat); } break; + + case KEY_ESC: + break; + + default: + b->button_modifier_mask &= ~button_get_keycode_modifier_mask(ev.code); + break; } } else if (ev.type == EV_SW && ev.value > 0) { @@ -342,7 +413,7 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u "MESSAGE_ID=" SD_MESSAGE_LID_CLOSED_STR); b->lid_closed = true; - button_lid_switch_handle_action(b->manager, true); + button_lid_switch_handle_action(b->manager, /* is_edge= */ true, b->seat); button_install_check_event_source(b); manager_send_changed(b->manager, "LidClosed", NULL); @@ -386,17 +457,25 @@ static int button_suitable(int fd) { return -errno; if (bitset_get(types, EV_KEY)) { - unsigned long keys[CONST_MAX5(KEY_POWER, KEY_POWER2, KEY_SLEEP, KEY_SUSPEND, KEY_RESTART)/ULONG_BITS+1]; + unsigned long keys[_KEY_MAX_INTERESTED/ULONG_BITS+1]; if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof keys), keys) < 0) return -errno; + /* If the device has power related keys, then accept the device. */ if (bitset_get(keys, KEY_POWER) || bitset_get(keys, KEY_POWER2) || bitset_get(keys, KEY_SLEEP) || bitset_get(keys, KEY_SUSPEND) || bitset_get(keys, KEY_RESTART)) return true; + + /* If the device has keys for the Secure Attention Key sequence, then accept the device. */ + if ((bitset_get(keys, KEY_LEFTSHIFT) || bitset_get(keys, KEY_RIGHTSHIFT)) && + (bitset_get(keys, KEY_LEFTCTRL) || bitset_get(keys, KEY_RIGHTCTRL)) && + (bitset_get(keys, KEY_LEFTALT) || bitset_get(keys, KEY_RIGHTALT)) && + bitset_get(keys, KEY_ESC)) + return true; } if (bitset_get(types, EV_SW)) { @@ -413,10 +492,27 @@ static int button_suitable(int fd) { return false; } +static int button_initialize_modifier_mask(Button *b) { + unsigned long keys[KEY_MAX/ULONG_BITS+1]; + + assert(b); + + if (ioctl(b->fd, EVIOCGKEY(sizeof(keys)), keys) < 0) + return log_error_errno(errno, "Failed to initialize modifier mask on /dev/input/%s: %m", b->name); + + b->button_modifier_mask = BUTTON_MODIFIER_NONE; + + FOREACH_ELEMENT(i, keycode_modifier_table) + if (bitset_get(keys, i->keycode)) + b->button_modifier_mask |= i->modifier_mask; + + return 0; +} + static int button_set_mask(const char *name, int fd) { unsigned long types[CONST_MAX(EV_KEY, EV_SW)/ULONG_BITS+1] = {}, - keys[CONST_MAX5(KEY_POWER, KEY_POWER2, KEY_SLEEP, KEY_SUSPEND, KEY_RESTART)/ULONG_BITS+1] = {}, + keys[_KEY_MAX_INTERESTED/ULONG_BITS+1] = {}, switches[CONST_MAX(SW_LID, SW_DOCK)/ULONG_BITS+1] = {}; struct input_mask mask; @@ -437,11 +533,11 @@ static int button_set_mask(const char *name, int fd) { return log_full_errno(IN_SET(errno, ENOTTY, EOPNOTSUPP, EINVAL) ? LOG_DEBUG : LOG_WARNING, errno, "Failed to set EV_SYN event mask on /dev/input/%s: %m", name); - bitset_put(keys, KEY_POWER); - bitset_put(keys, KEY_POWER2); - bitset_put(keys, KEY_SLEEP); - bitset_put(keys, KEY_SUSPEND); - bitset_put(keys, KEY_RESTART); + FOREACH_ELEMENT(key, keys_interested) { + assert(*key <= _KEY_MAX_INTERESTED); + + bitset_put(keys, *key); + } mask = (struct input_mask) { .type = EV_KEY, @@ -502,6 +598,11 @@ int button_open(Button *b) { b->fd = TAKE_FD(fd); log_info("Watching system buttons on %s (%s)", p, name); + + r = button_initialize_modifier_mask(b); + if (r < 0) + return r; + return 0; } diff --git a/src/login/logind-button.h b/src/login/logind-button.h index 6c39471fb44..125e49dd086 100644 --- a/src/login/logind-button.h +++ b/src/login/logind-button.h @@ -5,6 +5,20 @@ typedef struct Button Button; #include "logind.h" +typedef enum ButtonModifierMask { + BUTTON_MODIFIER_NONE = 0, + BUTTON_MODIFIER_LEFT_SHIFT = 1 << 0, + BUTTON_MODIFIER_RIGHT_SHIFT = 1 << 1, + BUTTON_MODIFIER_LEFT_CTRL = 1 << 2, + BUTTON_MODIFIER_RIGHT_CTRL = 1 << 3, + BUTTON_MODIFIER_LEFT_ALT = 1 << 4, + BUTTON_MODIFIER_RIGHT_ALT = 1 << 5, +} ButtonModifierMask; + +#define BUTTON_MODIFIER_HAS_SHIFT(modifier) (((modifier) & (BUTTON_MODIFIER_LEFT_SHIFT|BUTTON_MODIFIER_RIGHT_SHIFT)) != 0) +#define BUTTON_MODIFIER_HAS_CTRL(modifier) (((modifier) & (BUTTON_MODIFIER_LEFT_CTRL|BUTTON_MODIFIER_RIGHT_CTRL)) != 0) +#define BUTTON_MODIFIER_HAS_ALT(modifier) (((modifier) & (BUTTON_MODIFIER_LEFT_ALT|BUTTON_MODIFIER_RIGHT_ALT)) != 0) + struct Button { Manager *manager; @@ -15,6 +29,8 @@ struct Button { char *seat; int fd; + ButtonModifierMask button_modifier_mask; + bool lid_closed; bool docked; }; diff --git a/src/login/logind-core.c b/src/login/logind-core.c index 3d58cefc573..5e024c339de 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -50,6 +50,7 @@ void manager_reset_config(Manager *m) { m->handle_suspend_key_long_press = HANDLE_HIBERNATE; m->handle_hibernate_key = HANDLE_HIBERNATE; m->handle_hibernate_key_long_press = HANDLE_IGNORE; + m->handle_secure_attention_key = HANDLE_SECURE_ATTENTION_KEY; m->handle_lid_switch = HANDLE_SUSPEND; m->handle_lid_switch_ep = _HANDLE_ACTION_INVALID; @@ -696,6 +697,8 @@ bool manager_all_buttons_ignored(Manager *m) { return false; if (m->handle_lid_switch_docked != HANDLE_IGNORE) return false; + if (m->handle_secure_attention_key != HANDLE_IGNORE) + return false; return true; } diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 53ba291cab7..3e419bb62e5 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -3699,6 +3699,7 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("HandleLidSwitch", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("HandleLidSwitchExternalPower", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch_ep), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("HandleLidSwitchDocked", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch_docked), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HandleSecureAttentionKey", "s", property_get_handle_action, offsetof(Manager, handle_secure_attention_key), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("HoldoffTimeoutUSec", "t", NULL, offsetof(Manager, holdoff_timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("IdleAction", "s", property_get_handle_action, offsetof(Manager, idle_action), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("IdleActionUSec", "t", NULL, offsetof(Manager, idle_action_usec), SD_BUS_VTABLE_PROPERTY_CONST), @@ -4071,6 +4072,9 @@ static const sd_bus_vtable manager_vtable[] = { method_set_wall_message, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_SIGNAL_WITH_ARGS("SecureAttentionKey", + SD_BUS_ARGS("s", seat_id, "o", object_path), + 0), SD_BUS_SIGNAL_WITH_ARGS("SessionNew", SD_BUS_ARGS("s", session_id, "o", object_path), 0), diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf index f9d11e803e3..ce5af2ccfa7 100644 --- a/src/login/logind-gperf.gperf +++ b/src/login/logind-gperf.gperf @@ -37,6 +37,7 @@ Login.HandleHibernateKeyLongPress, config_parse_handle_action, 0, offse Login.HandleLidSwitch, config_parse_handle_action, 0, offsetof(Manager, handle_lid_switch) Login.HandleLidSwitchExternalPower, config_parse_handle_action, 0, offsetof(Manager, handle_lid_switch_ep) Login.HandleLidSwitchDocked, config_parse_handle_action, 0, offsetof(Manager, handle_lid_switch_docked) +Login.HandleSecureAttentionKey, config_parse_handle_action, 0, offsetof(Manager, handle_secure_attention_key) Login.PowerKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, power_key_ignore_inhibited) Login.SuspendKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, suspend_key_ignore_inhibited) Login.HibernateKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, hibernate_key_ignore_inhibited) diff --git a/src/login/logind.c b/src/login/logind.c index ac4b8602c4f..a0f7e08a2ab 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -1036,7 +1036,7 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us else log_info("System idle. Will %s now.", handle_action_verb_to_string(m->idle_action)); - manager_handle_action(m, 0, m->idle_action, false, is_edge); + manager_handle_action(m, /* inhibit_key= */ 0, m->idle_action, /* ignore_inhibited= */ false, is_edge, /* action_seat= */ NULL); m->idle_action_not_before_usec = n; } diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in index eb9452877a5..2e06b9a0501 100644 --- a/src/login/logind.conf.in +++ b/src/login/logind.conf.in @@ -36,6 +36,7 @@ #HandleLidSwitch=suspend #HandleLidSwitchExternalPower=suspend #HandleLidSwitchDocked=ignore +#HandleSecureAttentionKey=secure-attention-key #PowerKeyIgnoreInhibited=no #SuspendKeyIgnoreInhibited=no #HibernateKeyIgnoreInhibited=no diff --git a/src/login/logind.h b/src/login/logind.h index fbcfc9ab1b4..1e17b610bc8 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -109,6 +109,7 @@ struct Manager { HandleAction handle_suspend_key_long_press; HandleAction handle_hibernate_key; HandleAction handle_hibernate_key_long_press; + HandleAction handle_secure_attention_key; HandleAction handle_lid_switch; HandleAction handle_lid_switch_ep; diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h index 16e9986be36..f4f4e95b7fc 100644 --- a/src/systemd/sd-messages.h +++ b/src/systemd/sd-messages.h @@ -209,6 +209,8 @@ _SD_BEGIN_DECLARATIONS; #define SD_MESSAGE_POWER_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71) #define SD_MESSAGE_POWER_KEY_LONG_PRESS SD_ID128_MAKE(3e,01,17,10,1e,b2,43,c1,b9,a5,0d,b3,49,4a,b1,0b) #define SD_MESSAGE_POWER_KEY_LONG_PRESS_STR SD_ID128_MAKE_STR(3e,01,17,10,1e,b2,43,c1,b9,a5,0d,b3,49,4a,b1,0b) +#define SD_MESSAGE_SECURE_ATTENTION_KEY_PRESS SD_ID128_MAKE(b2,bc,ba,f5,ed,f9,48,e0,93,ce,50,bb,ea,0e,81,ec) +#define SD_MESSAGE_SECURE_ATTENTION_KEY_PRESS_STR SD_ID128_MAKE_STR(b2,bc,ba,f5,ed,f9,48,e0,93,ce,50,bb,ea,0e,81,ec) #define SD_MESSAGE_REBOOT_KEY SD_ID128_MAKE(9f,a9,d2,c0,12,13,4e,c3,85,45,1f,fe,31,6f,97,d0) #define SD_MESSAGE_REBOOT_KEY_STR SD_ID128_MAKE_STR(9f,a9,d2,c0,12,13,4e,c3,85,45,1f,fe,31,6f,97,d0) #define SD_MESSAGE_REBOOT_KEY_LONG_PRESS SD_ID128_MAKE(f1,c5,9a,58,c9,d9,43,66,89,65,c3,37,ca,ec,59,75)