File 0001-Use-Xauthority-for-Xwayland.patch of Package kwin5

From 10011387cd146f6b92f337b4c10ac4000c981891 Mon Sep 17 00:00:00 2001
From: Fabian Vogt <fabian@ritter-vogt.de>
Date: Sat, 17 Mar 2018 23:25:56 +0100
Subject: [PATCH] Use Xauthority for Xwayland
References: boo#1084737

Needed by kdesu, su, ...
If creation fails, it will fall back to not using it.
---
 CMakeLists.txt   |   1 +
 main_wayland.cpp | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 main_wayland.h   |   2 ++
 3 files changed, 102 insertions(+), 2 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index cbf9529ca..ba9ac6584 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -579,6 +579,7 @@ set(kwin_XLIB_LIBS
     ${X11_X11_LIB}
     ${X11_ICE_LIB}
     ${X11_SM_LIB}
+    ${X11_Xau_LIB}
 )
 
 set(kwin_XCB_LIBS
diff --git a/main_wayland.cpp b/main_wayland.cpp
index 2107bc85a..b3e5c6cf3 100644
--- a/main_wayland.cpp
+++ b/main_wayland.cpp
@@ -70,6 +70,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include <sys/capability.h>
 #endif
 
+#include <X11/Xauth.h>
+
 #include <sched.h>
 
 #include <iostream>
@@ -157,6 +159,16 @@ void ApplicationWayland::performStartup()
 {
     if (m_startXWayland) {
         setOperationMode(OperationModeXwayland);
+
+        QString dir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
+        if (!dir.isEmpty()) {
+            m_xwaylandAuthority.setFileTemplate(dir + QStringLiteral("/xauth_XXXXXX"));
+            m_xwaylandAuthority.open();
+        }
+
+        if (m_xwaylandAuthority.fileName().isEmpty()) {
+            std::cerr << "Warning: Could not create a Xauthority file for Xwayland." << std::endl;
+        }
     }
     // first load options - done internally by a different thread
     createOptions();
@@ -206,8 +218,89 @@ void ApplicationWayland::continueStartupWithSceen()
     notifyKSplash();
 }
 
+static QByteArray getRandomData(qint64 bytes)
+{
+    QFile random(QStringLiteral("/dev/urandom"));
+    if (!random.open(QIODevice::ReadOnly))
+        return {};
+
+    QByteArray data;
+    data.resize(bytes);
+    while (bytes) {
+        auto bytesRead = random.read(data.data() + data.size() - bytes, bytes);
+        if (bytesRead == -1)
+            return {};
+
+        bytes -= bytesRead;
+    }
+
+    return data;
+}
+
+static bool addCookieToFile(QString filename, QString &hostname)
+{
+    QByteArray cookie = getRandomData(16);
+    char *displayNumber = getenv("DISPLAY");
+
+    if(displayNumber == nullptr || displayNumber[0] == '\0' || cookie.count() != 16) {
+        return false;
+    }
+
+    FILE *authFp = fopen(qPrintable(filename), "wb");
+    if (authFp == nullptr) {
+        return false;
+    }
+
+    char localhost[HOST_NAME_MAX + 1] = "";
+    if (gethostname(localhost, HOST_NAME_MAX) < 0) {
+        strcpy(localhost, "localhost");
+    }
+
+    hostname = QString::fromUtf8(localhost);
+
+    Xauth auth = {};
+    char cookieName[] = "MIT-MAGIC-COOKIE-1";
+
+    auth.family = FamilyLocal;
+    auth.address = localhost;
+    auth.address_length = strlen(auth.address);
+    auth.number = displayNumber + 1;
+    auth.number_length = strlen(auth.number);
+    auth.name = cookieName;
+    auth.name_length = sizeof(cookieName) - 1;
+    auth.data = cookie.data();
+    auth.data_length = cookie.count();
+
+    if (XauWriteAuth(authFp, &auth) == 0) {
+        fclose(authFp);
+        return false;
+    }
+
+    auth.family = FamilyWild;
+    bool success = XauWriteAuth(authFp, &auth) != 0 && fflush(authFp) != EOF;
+
+    fclose(authFp);
+
+    return success;
+}
+
 void ApplicationWayland::continueStartupWithX()
 {
+    if (!m_xwaylandAuthority.fileName().isEmpty()) {
+        QString hostname;
+        if (addCookieToFile(m_xwaylandAuthority.fileName(), hostname)) {
+            setenv("XAUTHORITY", qPrintable(m_xwaylandAuthority.fileName()), 1);
+            setenv("XAUTHLOCALHOSTNAME", qPrintable(hostname), 1);
+            m_environment.insert(QStringLiteral("XAUTHORITY"), m_xwaylandAuthority.fileName());
+            m_environment.insert(QStringLiteral("XAUTHLOCALHOSTNAME"), hostname);
+        }
+        else {
+            std::cerr << "Could not generate Xauthority entry" << std::endl;
+            // We can't authenticate using it so the server must not see any entries either
+            m_xwaylandAuthority.resize(0);
+        }
+    }
+
     createX11Connection();
     xcb_connection_t *c = x11Connection();
     if (!c) {
@@ -377,11 +470,15 @@ void ApplicationWayland::startXwaylandServer()
     env.insert("WAYLAND_SOCKET", QByteArray::number(wlfd));
     env.insert("EGL_PLATFORM", QByteArrayLiteral("DRM"));
     m_xwaylandProcess->setProcessEnvironment(env);
-    m_xwaylandProcess->setArguments({QStringLiteral("-displayfd"),
+    QStringList args{QStringLiteral("-displayfd"),
                            QString::number(pipeFds[1]),
                            QStringLiteral("-rootless"),
                            QStringLiteral("-wm"),
-                           QString::number(fd)});
+                           QString::number(fd)};
+    if (!m_xwaylandAuthority.fileName().isEmpty()) {
+        args << QStringLiteral("-auth") << m_xwaylandAuthority.fileName();
+    }
+    m_xwaylandProcess->setArguments(args);
     m_xwaylandFailConnection = connect(m_xwaylandProcess, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), this,
         [] (QProcess::ProcessError error) {
             if (error == QProcess::FailedToStart) {
diff --git a/main_wayland.h b/main_wayland.h
index 31b7ebd55..37f9b2882 100644
--- a/main_wayland.h
+++ b/main_wayland.h
@@ -21,6 +21,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define KWIN_MAIN_WAYLAND_H
 #include "main.h"
 #include <QProcessEnvironment>
+#include <QTemporaryFile>
 
 class QProcess;
 
@@ -74,6 +75,7 @@ private:
     QMetaObject::Connection m_xwaylandFailConnection;
     QProcessEnvironment m_environment;
     QString m_sessionArgument;
+    QTemporaryFile m_xwaylandAuthority;
 };
 
 }
-- 
2.16.2