1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
6     SPDX-FileCopyrightText: 2021 David Edmundson <davidedmundson@kde.org>
7 
8     SPDX-License-Identifier: GPL-2.0-or-later
9 */
10 
11 #include "xauthority.h"
12 
13 #include <QDataStream>
14 #include <QRandomGenerator>
15 #include <QHostInfo>
16 #include <QTemporaryFile>
17 #include <QStandardPaths>
18 
writeXauthorityEntry(QDataStream & stream,quint16 family,const QByteArray & address,const QByteArray & display,const QByteArray & name,const QByteArray & cookie)19 static void writeXauthorityEntry(QDataStream &stream, quint16 family,
20                                  const QByteArray &address, const QByteArray &display,
21                                  const QByteArray &name, const QByteArray &cookie)
22 {
23     stream << quint16(family);
24 
25     auto writeArray = [&stream](const QByteArray &str) {
26         stream << quint16(str.size());
27         stream.writeRawData(str.constData(), str.size());
28     };
29 
30     writeArray(address);
31     writeArray(display);
32     writeArray(name);
33     writeArray(cookie);
34 }
35 
generateXauthorityCookie()36 static QByteArray generateXauthorityCookie()
37 {
38     QByteArray cookie;
39     cookie.resize(16); // Cookie must be 128bits
40 
41     QRandomGenerator *generator = QRandomGenerator::system();
42     for (int i = 0; i < cookie.size(); ++i) {
43         cookie[i] = uint8_t(generator->bounded(256));
44     }
45     return cookie;
46 }
47 
generateXauthorityFile(int display,QTemporaryFile * authorityFile)48 bool generateXauthorityFile(int display, QTemporaryFile *authorityFile)
49 {
50     const QString runtimeDirectory = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
51 
52     authorityFile->setFileTemplate(runtimeDirectory + QStringLiteral("/xauth_XXXXXX"));
53     if (!authorityFile->open()) {
54         return false;
55     }
56 
57     const QByteArray hostname = QHostInfo::localHostName().toUtf8();
58     const QByteArray displayName = QByteArray::number(display);
59     const QByteArray name = QByteArrayLiteral("MIT-MAGIC-COOKIE-1");
60     const QByteArray cookie = generateXauthorityCookie();
61 
62     QDataStream stream(authorityFile);
63     stream.setByteOrder(QDataStream::BigEndian);
64 
65     // Write entry with FamilyLocal and the host name as address
66     writeXauthorityEntry(stream, 256 /* FamilyLocal */, hostname, displayName, name, cookie);
67 
68     // Write entry with FamilyWild, no address
69     writeXauthorityEntry(stream, 65535 /* FamilyWild */, QByteArray{}, displayName, name, cookie);
70 
71     if (stream.status() != QDataStream::Ok || !authorityFile->flush()) {
72         authorityFile->remove();
73         return false;
74     }
75 
76     return true;
77 }
78