]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
login: Add a new SecureAttentionKey dbus signal when Ctrl+Alt+Shift+Esc is pressed
authornerdopolis <bluescreen_avenger@verizon.net>
Tue, 12 Mar 2024 02:09:07 +0000 (22:09 -0400)
committerLuca Boccassi <luca.boccassi@gmail.com>
Mon, 24 Jun 2024 20:29:38 +0000 (22:29 +0200)
14 files changed:
catalog/systemd.catalog.in
man/logind.conf.xml
man/org.freedesktop.login1.xml
src/login/logind-action.c
src/login/logind-action.h
src/login/logind-button.c
src/login/logind-button.h
src/login/logind-core.c
src/login/logind-dbus.c
src/login/logind-gperf.gperf
src/login/logind.c
src/login/logind.conf.in
src/login/logind.h
src/systemd/sd-messages.h

index 1a5f0aec89cf2507a18d30770d645a5f18561c8b..200c98eabe9239f84337fe1f2b62b50829c36d80 100644 (file)
@@ -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
index 9ec6cb1c400d3470f674ee3928d1df0a9932a9a6..66240b58fe867494506c3a6d261dcfb27894732f 100644 (file)
         <term><varname>HandleLidSwitch=</varname></term>
         <term><varname>HandleLidSwitchExternalPower=</varname></term>
         <term><varname>HandleLidSwitchDocked=</varname></term>
+        <term><varname>HandleSecureAttentionKey=</varname></term>
 
         <listitem><para>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
         <literal>ignore</literal>, <literal>poweroff</literal>, <literal>reboot</literal>, <literal>halt</literal>,
         <literal>kexec</literal>, <literal>suspend</literal>, <literal>hibernate</literal>, <literal>hybrid-sleep</literal>,
         <literal>suspend-then-hibernate</literal>, <literal>sleep</literal>, <literal>lock</literal>, and
-        <literal>factory-reset</literal>.  If <literal>ignore</literal>, <command>systemd-logind</command>
+        <literal>factory-reset</literal>, <literal>secure-attention-key</literal>.  If <literal>ignore</literal>, <command>systemd-logind</command>
         will never handle these keys. If <literal>lock</literal>, all running sessions will be screen-locked;
         otherwise, the specified action will be taken in the respective event. Only input devices with the
         <literal>power-switch</literal> udev tag will be watched for key/lid switch
         system is inserted in a docking station, or if more than one display is connected, the action
         specified by <varname>HandleLidSwitchDocked=</varname> occurs; if the system is on external power the
         action (if any) specified by <varname>HandleLidSwitchExternalPower=</varname> occurs; otherwise the
-        <varname>HandleLidSwitch=</varname> action occurs.</para>
+        <varname>HandleLidSwitch=</varname> action occurs.
+        <varname>HandleSecureAttentionKey=</varname> defaults to <literal>secure-attention-key</literal></para>
 
         <para>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
         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 <varname>Handle*=</varname>
-        settings are irrelevant.</para>
+        settings are irrelevant, except for <varname>HandleSecureAttentionKey=</varname>, which is always handled since its addition in v257.</para>
 
         <xi:include href="version-info.xml" xpointer="v184"/></listitem>
       </varlistentry>
index ad9b00e8eb0cd334a9164a45acd21b439e69bc64..cba371ca9e25df4a409ce351c083e281cb3360ea 100644 (file)
@@ -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 {
 
     <!--property HandleHibernateKeyLongPress is not documented!-->
 
+    <!--property HandleSecureAttentionKey is not documented!-->
+
     <!--property DesignatedMaintenanceTime is not documented!-->
 
     <!--property StopIdleSessionUSec is not documented!-->
@@ -430,6 +436,8 @@ node /org/freedesktop/login1 {
 
     <variablelist class="dbus-method" generated="True" extra-ref="SetWallMessage()"/>
 
+    <variablelist class="dbus-signal" generated="True" extra-ref="SecureAttentionKey()"/>
+
     <variablelist class="dbus-signal" generated="True" extra-ref="SessionNew()"/>
 
     <variablelist class="dbus-signal" generated="True" extra-ref="SessionRemoved()"/>
@@ -508,6 +516,8 @@ node /org/freedesktop/login1 {
 
     <variablelist class="dbus-property" generated="True" extra-ref="HandleLidSwitchDocked"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="HandleSecureAttentionKey"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="HoldoffTimeoutUSec"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="IdleAction"/>
@@ -733,6 +743,10 @@ node /org/freedesktop/login1 {
       <para>Whenever the inhibition state or idle hint changes, <function>PropertyChanged</function>
       signals are sent out to which clients can subscribe.</para>
 
+      <para>The <function>SecureAttentionKey()</function> 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.
+      </para>
+
       <para>The <function>SessionNew()</function>, <function>SessionRemoved()</function>,
       <function>UserNew()</function>, <function>UserRemoved()</function>, <function>SeatNew()</function>, and
       <function>SeatRemoved()</function> signals are sent each time a session is created or removed, a user
@@ -1590,6 +1604,8 @@ node /org/freedesktop/login1/session/1 {
       <varname>SleepOperation</varname>,
       <varname>DesignatedMaintenanceTime</varname>, and
       <function>ListSessionsEx()</function> were added in version 256.</para>
+      <para><varname>HandleSecureAttentionKey</varname>, and
+      <function>SecureAttentionKey()</function> were added in version 257.</para>
     </refsect2>
     <refsect2>
       <title>Session Objects</title>
index 9325d91549d5e5ac88d169307819145726a4b05f..686ba358f7e828ff3e0f299d787f653ee5689967 100644 (file)
@@ -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);
index c78c18c5aad635c16198a5a64cdb817bed760a58..800f4e830997c12f951a4befc2448c99183b625a 100644 (file)
@@ -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_;
 
index 14835aedc157c7a1a74202429de590f7978c9989..f980ea5eced9956b32772e157cd71b57366d56f3 100644 (file)
 #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;
 }
 
index 6c39471fb44f1cd6294b4538bb0f4d28cb1ad45c..125e49dd086464355f05b8d8b9643d407efe13a4 100644 (file)
@@ -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;
 };
index 3d58cefc57354774a83942c0078bab85028026b1..5e024c339de7a9d41cef3c58089ddf8218159a38 100644 (file)
@@ -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;
 }
index 53ba291cab776598e82cef2ae86f69f71925e0cb..3e419bb62e560fef6d5bffbd6292cbd797739abf 100644 (file)
@@ -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),
index f9d11e803e35bc5715933c70bde028037e1e605e..ce5af2ccfa7bf558a485af7d7f014602f924bedf 100644 (file)
@@ -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)
index ac4b8602c4f9b11816595a8148d02278ff268e97..a0f7e08a2ab46a23037abbd5d9fc386717ef7abd 100644 (file)
@@ -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;
                 }
 
index eb9452877a553769bafafa9059eebe595707396a..2e06b9a050199c58878b69948934b12b52bafbc9 100644 (file)
@@ -36,6 +36,7 @@
 #HandleLidSwitch=suspend
 #HandleLidSwitchExternalPower=suspend
 #HandleLidSwitchDocked=ignore
+#HandleSecureAttentionKey=secure-attention-key
 #PowerKeyIgnoreInhibited=no
 #SuspendKeyIgnoreInhibited=no
 #HibernateKeyIgnoreInhibited=no
index fbcfc9ab1b493895cec3c002a7db2960aeecf10d..1e17b610bc8c121004c64a62610654710636b5be 100644 (file)
@@ -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;
index 16e9986be36a10df9f3fa8880899679f88c1a42d..f4f4e95b7fca6be97fed1b0d22a127be5024345f 100644 (file)
@@ -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)