diff --git a/data/org_kde_kwin.categories b/data/org_kde_kwin.categories
index 6c03919d5e..8e788077e1 100644
--- a/data/org_kde_kwin.categories
+++ b/data/org_kde_kwin.categories
@@ -1,4 +1,5 @@
kwin_core KWin Core DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_CORE]
+kwin_utils KWin utils DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_UTILS]
kwin_virtualkeyboard KWin Virtual Keyboard Integration DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_VIRTUALKEYBOARD]
kwineffects KWin Effects DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWINEFFECTS]
libkwineffects KWin Effects Library DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [LIBKWINEFFECTS]
diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt
index 0ad5b212cb..0f2a0d48cc 100644
--- a/effects/CMakeLists.txt
+++ b/effects/CMakeLists.txt
@@ -23,6 +23,7 @@ set(kwin_effect_KDE_LIBS
KF5::Notifications # screenshot effect
KF5::Plasma # screenedge effect
KF5::WindowSystem
+ KF5::Service # utils / screenshot effect
)
if (HAVE_ACCESSIBILITY)
@@ -110,6 +111,7 @@ set(kwin4_effect_builtins_sources
windowgeometry/windowgeometry.cpp
wobblywindows/wobblywindows.cpp
zoom/zoom.cpp
+ ../service_utils.cpp
)
if (HAVE_ACCESSIBILITY)
diff --git a/effects/screenshot/CMakeLists.txt b/effects/screenshot/CMakeLists.txt
index c0f6d4a220..2b02cf5062 100644
--- a/effects/screenshot/CMakeLists.txt
+++ b/effects/screenshot/CMakeLists.txt
@@ -3,5 +3,6 @@
# Source files
set(kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources}
+ ../service_utils.cpp
screenshot/screenshot.cpp
)
diff --git a/effects/screenshot/screenshot.cpp b/effects/screenshot/screenshot.cpp
index a9817b4b57..14790182d4 100644
--- a/effects/screenshot/screenshot.cpp
+++ b/effects/screenshot/screenshot.cpp
@@ -27,6 +27,8 @@ along with this program. If not, see .
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -37,6 +39,7 @@ along with this program. If not, see .
#include
#include
+#include "../service_utils.h"
class ComparableQPoint : public QPoint
{
@@ -63,6 +66,8 @@ namespace KWin
const static QString s_errorAlreadyTaking = QStringLiteral("org.kde.kwin.Screenshot.Error.AlreadyTaking");
const static QString s_errorAlreadyTakingMsg = QStringLiteral("A screenshot is already been taken");
+const static QString s_errorNotAuthorized = QStringLiteral("org.kde.kwin.Screenshot.Error.NoAuthorized");
+const static QString s_errorNotAuthorizedMsg = QStringLiteral("The process is not authorized to take a screenshot");
const static QString s_errorFd = QStringLiteral("org.kde.kwin.Screenshot.Error.FileDescriptor");
const static QString s_errorFdMsg = QStringLiteral("No valid file descriptor");
const static QString s_errorCancelled = QStringLiteral("org.kde.kwin.Screenshot.Error.Cancelled");
@@ -71,6 +76,7 @@ const static QString s_errorInvalidArea = QStringLiteral("org.kde.kwin.Screensho
const static QString s_errorInvalidAreaMsg = QStringLiteral("Invalid area requested");
const static QString s_errorInvalidScreen = QStringLiteral("org.kde.kwin.Screenshot.Error.InvalidScreen");
const static QString s_errorInvalidScreenMsg = QStringLiteral("Invalid screen requested");
+const static QString s_dbusInterfaceName = QStringLiteral("org.kde.kwin.Screenshot");
bool ScreenShotEffect::supported()
{
@@ -496,13 +502,35 @@ void ScreenShotEffect::screenshotForWindow(qulonglong winid, int mask)
}
}
-QString ScreenShotEffect::interactive(int mask)
+bool ScreenShotEffect::checkCall() const
{
if (!calledFromDBus()) {
- return QString();
+ return false;
}
+
+ const QDBusReply reply = connection().interface()->servicePid(message().service());
+ if (reply.isValid()) {
+ const uint pid = reply.value();
+ const auto interfaces = KWin::fetchRestrictedDBusInterfacesFromPid(pid);
+ if (!interfaces.contains(s_dbusInterfaceName)) {
+ sendErrorReply(s_errorNotAuthorized, s_errorNotAuthorizedMsg);
+ qCWarning(KWINEFFECTS) << "Process " << pid << " tried to take a screenshot without being granted to DBus interface" << s_dbusInterfaceName;
+ return false;
+ }
+ } else {
+ return false;
+ }
+
if (isTakingScreenshot()) {
sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg);
+ return false;
+ }
+ return true;
+}
+
+QString ScreenShotEffect::interactive(int mask)
+{
+ if (!checkCall()) {
return QString();
}
m_type = (ScreenShotType) mask;
@@ -528,11 +556,7 @@ QString ScreenShotEffect::interactive(int mask)
void ScreenShotEffect::interactive(QDBusUnixFileDescriptor fd, int mask)
{
- if (!calledFromDBus()) {
- return;
- }
- if (isTakingScreenshot()) {
- sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg);
+ if (!checkCall()) {
return;
}
m_fd = dup(fd.fileDescriptor());
@@ -581,11 +605,7 @@ void ScreenShotEffect::hideInfoMessage()
QString ScreenShotEffect::screenshotFullscreen(bool captureCursor)
{
- if (!calledFromDBus()) {
- return QString();
- }
- if (isTakingScreenshot()) {
- sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg);
+ if (!checkCall()) {
return QString();
}
m_replyMessage = message();
@@ -598,11 +618,7 @@ QString ScreenShotEffect::screenshotFullscreen(bool captureCursor)
void ScreenShotEffect::screenshotFullscreen(QDBusUnixFileDescriptor fd, bool captureCursor, bool shouldReturnNativeSize)
{
- if (!calledFromDBus()) {
- return;
- }
- if (isTakingScreenshot()) {
- sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg);
+ if (!checkCall()) {
return;
}
m_fd = dup(fd.fileDescriptor());
@@ -613,29 +629,13 @@ void ScreenShotEffect::screenshotFullscreen(QDBusUnixFileDescriptor fd, bool cap
m_captureCursor = captureCursor;
m_nativeSize = shouldReturnNativeSize;
- showInfoMessage(InfoMessageMode::Screen);
- effects->startInteractivePositionSelection(
- [this] (const QPoint &p) {
- hideInfoMessage();
- if (p == QPoint(-1, -1)) {
- // error condition
- close(m_fd);
- m_fd = -1;
- } else {
- m_scheduledGeometry = effects->virtualScreenGeometry();
- effects->addRepaint(m_scheduledGeometry);
- }
- }
- );
+ m_scheduledGeometry = effects->virtualScreenGeometry();
+ effects->addRepaint(m_scheduledGeometry);
}
QString ScreenShotEffect::screenshotScreen(int screen, bool captureCursor)
{
- if (!calledFromDBus()) {
- return QString();
- }
- if (isTakingScreenshot()) {
- sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg);
+ if (!checkCall()) {
return QString();
}
m_scheduledGeometry = effects->clientArea(FullScreenArea, screen, 0);
@@ -652,11 +652,7 @@ QString ScreenShotEffect::screenshotScreen(int screen, bool captureCursor)
void ScreenShotEffect::screenshotScreen(QDBusUnixFileDescriptor fd, bool captureCursor)
{
- if (!calledFromDBus()) {
- return;
- }
- if (isTakingScreenshot()) {
- sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg);
+ if (!checkCall()) {
return;
}
m_fd = dup(fd.fileDescriptor());
@@ -689,11 +685,7 @@ void ScreenShotEffect::screenshotScreen(QDBusUnixFileDescriptor fd, bool capture
QString ScreenShotEffect::screenshotArea(int x, int y, int width, int height, bool captureCursor)
{
- if (!calledFromDBus()) {
- return QString();
- }
- if (isTakingScreenshot()) {
- sendErrorReply(s_errorAlreadyTaking, s_errorAlreadyTakingMsg);
+ if (!checkCall()) {
return QString();
}
m_scheduledGeometry = QRect(x, y, width, height);
diff --git a/effects/screenshot/screenshot.h b/effects/screenshot/screenshot.h
index cfb080f618..1c573680bf 100644
--- a/effects/screenshot/screenshot.h
+++ b/effects/screenshot/screenshot.h
@@ -154,6 +154,7 @@ private:
void hideInfoMessage();
bool isTakingScreenshot() const;
void computeCoordinatesAfterScaling();
+ bool checkCall() const;
EffectWindow *m_scheduledScreenshot;
ScreenShotType m_type;
diff --git a/service_utils.cpp b/service_utils.cpp
new file mode 100644
index 0000000000..17ec434ff4
--- /dev/null
+++ b/service_utils.cpp
@@ -0,0 +1,32 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2020, Méven Car
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+
+/*
+
+ This file is for (very) small utility relating to services/process.
+
+*/
+#include "service_utils.h"
+
+namespace KWin
+{
+
+}// namespace
+
diff --git a/service_utils.h b/service_utils.h
new file mode 100644
index 0000000000..8fe953238b
--- /dev/null
+++ b/service_utils.h
@@ -0,0 +1,77 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2020, Méven Car
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+
+#ifndef SERVICE_UTILS_H
+#define SERVICE_UTILS_H
+
+// cmake stuff
+#include
+// kwin
+#include
+// Qt
+#include
+#include
+//KF
+#include
+
+namespace KWin
+{
+
+const static QString s_waylandInterfaceName = QStringLiteral("X-KDE-Wayland-Interfaces");
+const static QString s_dbusRestrictedInterfaceName = QStringLiteral("X-KDE-DBUS-Restricted-Interfaces");
+
+static QStringList fetchProcessServiceField(const QString &executablePath, const QString &fieldName)
+{
+ // needed to be able to use the logging category in a header static function
+ static QLoggingCategory KWIN_UTILS ("KWIN_UTILS");
+ const auto servicesFound = KApplicationTrader::query([&executablePath] (const KService::Ptr &service) {
+
+ if (service->exec().isEmpty() || service->exec() != executablePath)
+ return false;
+
+ return true;
+ });
+
+ if (servicesFound.isEmpty()) {
+ qCDebug(KWIN_UTILS) << "Could not find the desktop file for" << executablePath;
+ return {};
+ }
+
+ const auto fieldValues = servicesFound.first()->property(fieldName).toStringList();
+ if (KWIN_UTILS().isDebugEnabled()) {
+ qCDebug(KWIN_UTILS) << "Interfaces found for" << executablePath << fieldName << ":" << fieldValues;
+ }
+ return fieldValues;
+}
+
+static QStringList fetchRequestedInterfaces(const QString &executablePath)
+{
+ return fetchProcessServiceField(executablePath, s_waylandInterfaceName);
+}
+
+static QStringList fetchRestrictedDBusInterfacesFromPid(const uint pid)
+{
+ const auto executablePath = QFileInfo(QStringLiteral("/proc/%1/exe").arg(pid)).symLinkTarget();
+ return fetchProcessServiceField(executablePath, s_dbusRestrictedInterfaceName);
+}
+
+}// namespace
+
+#endif // SERVICE_UTILS_H
diff --git a/wayland_server.cpp b/wayland_server.cpp
index cc1aec5908..7b51754d9a 100644
--- a/wayland_server.cpp
+++ b/wayland_server.cpp
@@ -26,6 +26,7 @@ along with this program. If not, see .
#include "waylandxdgshellintegration.h"
#include "workspace.h"
#include "xdgshellclient.h"
+#include "service_utils.h"
// Client
#include
@@ -68,9 +69,6 @@ along with this program. If not, see .
#include
#include
-// KF
-#include
-
// Qt
#include
#include
@@ -243,17 +241,7 @@ public:
}
QStringList fetchRequestedInterfaces(KWaylandServer::ClientConnection *client) const {
- const auto serviceQuery = QStringLiteral("exist Exec and exist [X-KDE-Wayland-Interfaces] and '%1' =~ Exec").arg(client->executablePath());
- const auto servicesFound = KServiceTypeTrader::self()->query(QStringLiteral("Application"), serviceQuery);
-
- if (servicesFound.isEmpty()) {
- qCDebug(KWIN_CORE) << "Could not find the desktop file for" << client->executablePath();
- return {};
- }
-
- const auto interfaces = servicesFound.first()->property("X-KDE-Wayland-Interfaces").toStringList();
- qCDebug(KWIN_CORE) << "Interfaces for" << client->executablePath() << interfaces;
- return interfaces;
+ return KWin::fetchRequestedInterfaces(client->executablePath());
}
const QSet interfacesBlackList = {"org_kde_kwin_remote_access_manager", "org_kde_plasma_window_management", "org_kde_kwin_fake_input", "org_kde_kwin_keystate"};