File indexing completed on 2021-12-21 14:17:29

0001 /********************************************************************
0002  KSld - the KDE Screenlocker Daemon
0003  This file is part of the KDE project.
0004 
0005 Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007 This program is free software; you can redistribute it and/or modify
0008 it under the terms of the GNU General Public License as published by
0009 the Free Software Foundation; either version 2 of the License, or
0010 (at your option) any later version.
0011 
0012 This program is distributed in the hope that it will be useful,
0013 but WITHOUT ANY WARRANTY; without even the implied warranty of
0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015 GNU General Public License for more details.
0016 
0017 You should have received a copy of the GNU General Public License
0018 along with this program.  If not, see <http://www.gnu.org/licenses/>.
0019 *********************************************************************/
0020 #ifndef GLOBALACCEL_H
0021 #define GLOBALACCEL_H
0022 
0023 #include <KGlobalShortcutInfo>
0024 
0025 #include <QMap>
0026 #include <QObject>
0027 
0028 class QDBusPendingCallWatcher;
0029 class QKeyEvent;
0030 
0031 struct xcb_key_press_event_t;
0032 typedef struct _XCBKeySymbols xcb_key_symbols_t;
0033 
0034 /**
0035  * @short Interaction with KGlobalAccel.
0036  *
0037  * While the screen is locked, we want a few white listed global shortcuts to activate.
0038  * While the screen is locked KGlobalAcceld is not functional as the screen locker holds an
0039  * active X11 key grab and KGlobalAcceld does not get the key events. This prevents useful keys,
0040  * like volume control to no longer function.
0041  *
0042  * This class circumvents the problem by interacting with KGlobalAccel when the screen is locked
0043  * to still allow a few white listed shortcuts (like volume control) to function.
0044  *
0045  * As the screen is locked we can operate on a few assumptions which simplifies the interaction:
0046  * shortcuts won't change. The user cannot interact with the system thus the global shortcut won't
0047  * change while the screen is locked. This allows us to fetch the allowed shortcut information from
0048  * KGlobalAcceld when the screen gets locked and keep these information around till the screen is
0049  * unlocked. We do not need to update the information while the screen is locked.
0050  *
0051  * As the information is fetched in an async way from KGlobalAcceld there is a short time window
0052  * when the screen is locked, but the shortcut information is not fetched. This is considered a
0053  * not relevant corner case as we can assume that right when the screen locks (due to e.g. idle)
0054  * no user is in front of the system and is not able to press the shortcut or that the user directly
0055  * wants to cancel the lock screen again (grace time).
0056  *
0057  * Components are just registered by name in KGlobalAccel. This would in theory allow a malicious
0058  * application to register under a white listed name with white listed shortcuts and bind enough
0059  * shortcuts to turn this functionality into a key grabber to read the users password. To prevent such
0060  * attacks the shortcuts which can be invoked are restricted: the triggered key may not be a single
0061  * key in alphanumeric area with or without the shift keys. If a global shortcut contains an
0062  * alphanumeric key it will only be handled if also an additional modifier like Alt of Meta is pressed.
0063  **/
0064 class GlobalAccel : public QObject
0065 {
0066     Q_OBJECT
0067 public:
0068     explicit GlobalAccel(QObject *parent = nullptr);
0069 
0070     /**
0071      * Starts interacting with KGlobalAccel and fetches the up-to-date shortcut information.
0072      **/
0073     void prepare();
0074     /**
0075      * Discards all knowing shortcut information.
0076      **/
0077     void release();
0078 
0079     /**
0080      * Checks whether a global shortcut is triggered for the given @p event.
0081      * If there is a global shortcut it gets invoked and @c true is returned.
0082      * If there is no matching global shortcut @c false is returned.
0083      **/
0084     bool checkKeyPress(xcb_key_press_event_t *event);
0085 
0086     bool keyEvent(QKeyEvent *event);
0087 
0088 private:
0089     void components(QDBusPendingCallWatcher *watcher);
0090     /**
0091      * Recursion check: for each DBus call to KGlobalAccel this counter is
0092      * increased, on each reply decreased. As long as we have running DBus
0093      * calls, we do not enter prepare again.
0094      *
0095      * This ensures that if the screen gets locked, unlocked, locked in a short
0096      * time while we are still fetching information from KGlobalAccel we do not
0097      * enter an incorrect state.
0098      **/
0099     uint m_updatingInformation = 0;
0100     /**
0101      * The shortcuts which got fetched from KGlobalAccel and can be operated on.
0102      * The key of contains the component DBus object path, the value the list of
0103      * allowed shortcuts.
0104      **/
0105     QMap<QString, QList<KGlobalShortcutInfo>> m_shortcuts;
0106     xcb_key_symbols_t *m_keySymbols = nullptr;
0107 };
0108 
0109 #endif