diff --git a/.gitignore b/.gitignore index d01f115..aa7fb6f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /e707e22901049495818a9bedf71f0ba829564700.tar.gz /50ca5b20354b6d338ce8836a613af19cedb1dca2.tar.gz /7a008602f5f0a4ed8586ce24012983458a687d4e.tar.gz +/db1d7381754a01a69b0f4c579c0267d80183c066.tar.gz diff --git a/sddm-0.2.0-0.11.20130914git50ca5b20-xdmcp.patch b/sddm-0.2.0-0.11.20130914git50ca5b20-xdmcp.patch deleted file mode 100644 index b145c68..0000000 --- a/sddm-0.2.0-0.11.20130914git50ca5b20-xdmcp.patch +++ /dev/null @@ -1,1618 +0,0 @@ -diff --git a/data/sddm.conf.in b/data/sddm.conf.in -index 9522ffd..204dc52 100644 ---- a/data/sddm.conf.in -+++ b/data/sddm.conf.in -@@ -89,3 +89,6 @@ MinimumVT=7 - # Valid values: on|off|none - # If property is set to none, numlock won't be changed - Numlock=none -+ -+# Enables the XDMCP Server -+XDMCPServer=false -\ No newline at end of file -diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index a82ae45..1d6d117 100644 ---- a/src/CMakeLists.txt -+++ b/src/CMakeLists.txt -@@ -20,6 +20,9 @@ set(DAEMON_SOURCES - daemon/Session.cpp - daemon/SignalHandler.cpp - daemon/SocketServer.cpp -+ daemon/xdmcp/Packet.cpp -+ daemon/xdmcp/Server.cpp -+ daemon/xdmcp/Utils.cpp - ) - - if(USE_QT5) -diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp -index 2095b05..4b780b3 100644 ---- a/src/common/Configuration.cpp -+++ b/src/common/Configuration.cpp -@@ -63,6 +63,7 @@ namespace SDDM { - bool autoRelogin { false }; - - Configuration::NumState numlock { Configuration::NUM_NONE }; -+ bool xdmcpServerEnabled { false }; - }; - - Configuration::Configuration(const QString &configPath, QObject *parent) : QObject(parent), d(new ConfigurationPrivate()) { -@@ -122,6 +123,7 @@ namespace SDDM { - } else { - d->numlock = Configuration::NUM_NONE; - } -+ d->xdmcpServerEnabled = settings.value("XDMCPServer", d->xdmcpServerEnabled).toBool(); - } - - void Configuration::save() { -@@ -158,6 +160,8 @@ namespace SDDM { - settings.setValue("Numlock", "on"); - else if (d->numlock == NUM_SET_OFF) - settings.setValue("Numlock", "off"); -+ -+ settings.setValue("XDMCPServer", d->xdmcpServerEnabled); - } - - Configuration *Configuration::instance() { -@@ -261,4 +265,9 @@ namespace SDDM { - const Configuration::NumState Configuration::numlock() const { - return d->numlock; - } -+ -+ bool Configuration::xdmcpServerEnabled() const { -+ return d->xdmcpServerEnabled; -+ } -+ - } -diff --git a/src/common/Configuration.h b/src/common/Configuration.h -index cbef261..4b610d8 100644 ---- a/src/common/Configuration.h -+++ b/src/common/Configuration.h -@@ -79,6 +79,8 @@ namespace SDDM { - enum NumState { NUM_NONE, NUM_SET_ON, NUM_SET_OFF }; - const NumState numlock() const; - -+ bool xdmcpServerEnabled() const; -+ - bool first { true }; - - bool testing { false }; -diff --git a/src/daemon/DaemonApp.cpp b/src/daemon/DaemonApp.cpp -index 9ad226b..9feb734 100644 ---- a/src/daemon/DaemonApp.cpp -+++ b/src/daemon/DaemonApp.cpp -@@ -25,6 +25,7 @@ - #include "PowerManager.h" - #include "SeatManager.h" - #include "SignalHandler.h" -+#include "xdmcp/Server.h" - - #ifdef USE_QT5 - #include "MessageHandler.h" -@@ -65,6 +66,12 @@ namespace SDDM { - // create seat manager - m_seatManager = new SeatManager(this); - -+ // start the XDMCP server -+ if (configuration()->xdmcpServerEnabled()) { -+ m_xdmcpServer = XDMCP::Server::instance(this); -+ m_xdmcpServer->start(); -+ } -+ - // connect with display manager - connect(m_seatManager, SIGNAL(seatCreated(QString)), m_displayManager, SLOT(AddSeat(QString))); - connect(m_seatManager, SIGNAL(seatRemoved(QString)), m_displayManager, SLOT(RemoveSeat(QString))); -diff --git a/src/daemon/DaemonApp.h b/src/daemon/DaemonApp.h -index 81f955c..2088010 100644 ---- a/src/daemon/DaemonApp.h -+++ b/src/daemon/DaemonApp.h -@@ -29,6 +29,9 @@ namespace SDDM { - class DisplayManager; - class PowerManager; - class SeatManager; -+ namespace XDMCP { -+ class Server; -+ } - - class DaemonApp : public QCoreApplication { - Q_OBJECT -@@ -57,6 +60,7 @@ namespace SDDM { - DisplayManager *m_displayManager { nullptr }; - PowerManager *m_powerManager { nullptr }; - SeatManager *m_seatManager { nullptr }; -+ XDMCP::Server *m_xdmcpServer { nullptr }; - }; - } - -diff --git a/src/daemon/Display.cpp b/src/daemon/Display.cpp -index f1a54b4..48137e6 100644 ---- a/src/daemon/Display.cpp -+++ b/src/daemon/Display.cpp -@@ -53,6 +53,17 @@ namespace SDDM { - return name; - } - -+ Display::Display(const QString& hostname, const int displayId, QObject* parent) : QObject(parent), -+ m_displayId(displayId), -+ m_authenticator(new Authenticator(this)), -+ m_displayServer(nullptr), -+ m_socketServer(new SocketServer(this)), -+ m_greeter(new Greeter(this)) { -+ m_display = QString("%1:%2").arg(hostname).arg(displayId); -+ -+ init(); -+ } -+ - Display::Display(const int displayId, const int terminalId, Seat *parent) : QObject(parent), - m_displayId(displayId), m_terminalId(terminalId), - m_authenticator(new Authenticator(this)), -@@ -63,12 +74,17 @@ namespace SDDM { - - m_display = QString(":%1").arg(m_displayId); - -- // restart display after user session ended -- connect(m_authenticator, SIGNAL(stopped()), this, SLOT(stop())); -- - // restart display after display server ended - connect(m_displayServer, SIGNAL(stopped()), this, SLOT(stop())); - -+ init(); -+ } -+ -+ void Display::init() -+ { -+ // restart display after user session ended -+ connect(m_authenticator, SIGNAL(stopped()), this, SLOT(stop())); -+ - // connect login signal - connect(m_socketServer, SIGNAL(login(QLocalSocket*,QString,QString,QString)), this, SLOT(login(QLocalSocket*,QString,QString,QString))); - -@@ -91,6 +107,22 @@ namespace SDDM { - - // set socket name - m_socket = QString("sddm-%1-%2").arg(m_display).arg(generateName(6)); -+ -+ // generate cookie -+ std::random_device rd; -+ std::mt19937 gen(rd()); -+ std::uniform_int_distribution<> dis(0, 15); -+ -+ // resever 32 bytes -+ m_cookie.reserve(32); -+ -+ // create a random hexadecimal number -+ const char *digits = "0123456789abcdef"; -+ for (int i = 0; i < 32; ++i) -+ m_cookie[i] = digits[dis(gen)]; -+ -+ // generate auth file -+ addCookie(m_authPath); - } - - Display::~Display() { -@@ -113,6 +145,16 @@ namespace SDDM { - return m_cookie; - } - -+ const QByteArray Display::rawCookie() const { -+ QByteArray cookie; -+ for (int i = 0; i < m_cookie.length() / 2; i++) { -+ // horrible, just horrible -+ quint8 byte = QString("%1%2").arg(m_cookie[i*2]).arg(m_cookie[i*2+1]).toUInt(nullptr, 16); -+ cookie.append(byte); -+ } -+ return cookie; -+ } -+ - Seat *Display::seat() const { - return m_seat; - } -@@ -144,28 +186,14 @@ namespace SDDM { - if (m_started) - return; - -- // generate cookie -- std::random_device rd; -- std::mt19937 gen(rd()); -- std::uniform_int_distribution<> dis(0, 15); -+ if (m_displayServer != nullptr) { -+ // set display server params -+ m_displayServer->setDisplay(m_display); -+ m_displayServer->setAuthPath(m_authPath); - -- // resever 32 bytes -- m_cookie.reserve(32); -- -- // create a random hexadecimal number -- const char *digits = "0123456789abcdef"; -- for (int i = 0; i < 32; ++i) -- m_cookie[i] = digits[dis(gen)]; -- -- // generate auth file -- addCookie(m_authPath); -- -- // set display server params -- m_displayServer->setDisplay(m_display); -- m_displayServer->setAuthPath(m_authPath); -- -- // start display server -- m_displayServer->start(); -+ // start display server -+ m_displayServer->start(); -+ } - - if ((daemonApp->configuration()->first || daemonApp->configuration()->autoRelogin()) && - !daemonApp->configuration()->autoUser().isEmpty() && !daemonApp->configuration()->lastSession().isEmpty()) { -@@ -221,9 +249,11 @@ namespace SDDM { - m_socketServer->stop(); - - // stop display server -- m_displayServer->blockSignals(true); -- m_displayServer->stop(); -- m_displayServer->blockSignals(false); -+ if (m_displayServer != nullptr) { -+ m_displayServer->blockSignals(true); -+ m_displayServer->stop(); -+ m_displayServer->blockSignals(false); -+ } - - // remove authority file - QFile::remove(m_authPath); -diff --git a/src/daemon/Display.h b/src/daemon/Display.h -index 46d320b..9556209 100644 ---- a/src/daemon/Display.h -+++ b/src/daemon/Display.h -@@ -35,6 +35,7 @@ namespace SDDM { - Q_OBJECT - Q_DISABLE_COPY(Display) - public: -+ explicit Display(const QString& hostname, const int displayId, QObject *parent = 0); - explicit Display(const int displayId, const int terminalId, Seat *parent); - ~Display(); - -@@ -44,6 +45,7 @@ namespace SDDM { - const QString &name() const; - - const QString &cookie() const; -+ const QByteArray rawCookie() const; - void addCookie(const QString &file); - - Seat *seat() const; -@@ -61,6 +63,8 @@ namespace SDDM { - void loginSucceeded(QLocalSocket *socket); - - private: -+ void init(); -+ - bool m_relogin { true }; - bool m_started { false }; - -diff --git a/src/daemon/xdmcp/Packet.cpp b/src/daemon/xdmcp/Packet.cpp -new file mode 100644 -index 0000000..3a0c3d9 ---- /dev/null -+++ b/src/daemon/xdmcp/Packet.cpp -@@ -0,0 +1,397 @@ -+/* -+ * Packet type handling for X Display Control Protocol -+ * Copyright (C) 2013 Martin Bříza -+ * -+ * 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, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ * -+ */ -+ -+#include "Packet.h" -+#include "Server.h" -+#include "../Display.h" -+ -+namespace SDDM { -+namespace XDMCP { -+ -+/******************************************************************************* -+* PLUMBING -+ ******************************************************************************/ -+ -+ Packet::Packet(const QHostAddress &host, quint16 port) : m_host(host), -+ m_port(port), -+ m_valid(true) { -+ -+ } -+ -+ Packet::Packet(const QHostAddress &host, quint16 port, Reader &r) : m_host(host), -+ m_port(port), -+ m_valid(false) { -+ -+ } -+ -+ Packet::~Packet() { -+ -+ } -+ -+ bool Packet::isValid() const { -+ return m_valid; -+ } -+ -+ // static -+ Packet *Packet::decode(const QByteArray &data, const QHostAddress &host, quint16 port) { -+ Reader reader(data); -+ uint16_t version, opcode, length; -+ -+ reader >> version >> opcode >> length; -+ -+ if (version != 1) -+ return nullptr; -+ if (length != data.size() - 6) -+ return nullptr; -+ -+ switch (opcode) { -+ case _Query: -+ return new Query(host, port, reader); -+ case _BroadcastQuery: -+ return new BroadcastQuery(host, port, reader); -+ case _IndirectQuery: -+ return new IndirectQuery(host, port, reader); -+ case _ForwardQuery: -+ return new ForwardQuery(host, port, reader); -+ case _Willing: -+ return new Willing(host, port, reader); -+ case _Unwilling: -+ return new Unwilling(host, port, reader); -+ case _Request: -+ return new Request(host, port, reader); -+ case _Accept: -+ return new Accept(host, port, reader); -+ case _Decline: -+ return new Decline(host, port, reader); -+ case _Manage: -+ return new Manage(host, port, reader); -+ case _Refuse: -+ return new Refuse(host, port, reader); -+ case _Failed: -+ return new Failed(host, port, reader); -+ case _KeepAlive: -+ return new KeepAlive(host, port, reader); -+ case _Alive: -+ return new Alive(host, port, reader); -+ default: -+ qDebug() << " XDMCP: Got packet of an unknown type" << opcode; -+ return nullptr; -+ } -+ } -+ -+ void Packet::setHost(const QHostAddress &host) { -+ m_host = QHostAddress(host); -+ } -+ -+ const QHostAddress& Packet::host() const { -+ return m_host; -+ } -+ -+ void Packet::setPort(quint16 port) { -+ m_port = port; -+ } -+ -+ quint16 Packet::port() const { -+ return m_port; -+ } -+ -+ QByteArray Packet::encode() const { -+ return QByteArray(); -+ } -+ -+ Packet *Packet::onClientReceived() const { -+ qDebug() << " XDMCP: Client received a wrong packet type (no action assigned)"; -+ return nullptr; -+ } -+ -+ Packet *Packet::onServerReceived() const { -+ qDebug() << " XDMCP: Server received a wrong packet type (no action assigned)"; -+ return nullptr; -+ } -+ -+ Packet::Query::Query(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_authenticationNames; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::Query::encode() const { -+ Writer w; -+ w << m_authenticationNames; -+ return w.finalize(Packet::_Query); -+ } -+ -+ Packet::BroadcastQuery::BroadcastQuery(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_authenticationNames; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::BroadcastQuery::encode() const { -+ Writer w; -+ w << m_authenticationNames; -+ return w.finalize(Packet::_BroadcastQuery); -+ } -+ -+ Packet::IndirectQuery::IndirectQuery(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_authenticationNames; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::IndirectQuery::encode() const { -+ Writer w; -+ w << m_authenticationNames; -+ return w.finalize(Packet::_IndirectQuery); -+ } -+ -+ Packet::ForwardQuery::ForwardQuery(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_clientAddress >> m_clientPort >> m_authenticationNames; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::ForwardQuery::encode() const { -+ Writer w; -+ w << m_clientAddress << m_clientPort << m_authenticationNames; -+ return w.finalize(Packet::_ForwardQuery); -+ } -+ -+ Packet::Willing::Willing(const QHostAddress &host, quint16 port, const QString &authenticationName, const QString &hostname, const QString &status) : Packet(host, port), -+ m_authenticationName(authenticationName.toLatin1()), -+ m_hostname(hostname.toLatin1()), -+ m_status(status.toLatin1()) { -+ qDebug() << " XDMCP: Prepared Willing reply for" << host << port << "with contents" << authenticationName << hostname << status; -+ } -+ -+ Packet::Willing::Willing(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_authenticationName >> m_hostname >> m_status; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::Willing::encode() const { -+ Writer w; -+ w << m_authenticationName << m_hostname << m_status; -+ return w.finalize(Packet::_Willing); -+ } -+ -+ Packet::Unwilling::Unwilling(const QHostAddress &host, quint16 port, const QString &hostname, const QString &status) : Packet(host, port), -+ m_hostname(hostname.toLatin1()), -+ m_status(status.toLatin1()) { -+ qDebug() << " XDMCP: Prepared Unwilling reply for" << host << port << "with contents" << hostname << status; -+ } -+ -+ Packet::Unwilling::Unwilling(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_hostname >> m_status; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::Unwilling::encode() const { -+ Writer w; -+ w << m_hostname << m_status; -+ return w.finalize(Packet::_Unwilling); -+ } -+ -+ Packet::Request::Request(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_displayNumber >> m_connectionTypes >> m_connectionAddresses >> m_authenticationName >> m_authenticationData >> m_authorizationNames >> m_manufacturerDisplayID; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::Request::encode() const { -+ Writer w; -+ w << m_displayNumber << m_connectionTypes << m_connectionAddresses << m_authenticationName << m_authenticationData << m_authorizationNames << m_manufacturerDisplayID; -+ return w.finalize(Packet::_Request); -+ } -+ -+ Packet::Accept::Accept(const QHostAddress &host, quint16 port, uint32_t sessionId, const QString authenticationName, const QByteArray authenticationData, const QString authorizationName, const QByteArray authorizationData) : Packet(host, port), -+ m_sessionID(sessionId), -+ m_authenticationName(authenticationName.toLatin1()), -+ m_authenticationData(authenticationData), -+ m_authorizationName(authorizationName.toLatin1()), -+ m_authorizationData(authorizationData) { -+ qDebug() << " XDMCP: Prepared Accept reply for" << host << port << "with contents" << sessionId << authenticationName << authenticationData << authorizationName << authorizationData; -+ } -+ -+ Packet::Accept::Accept(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_sessionID >> m_authenticationName >> m_authenticationData >> m_authorizationName >> m_authorizationData; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::Accept::encode() const { -+ Writer w; -+ w << m_sessionID << m_authenticationName << m_authenticationData << m_authorizationName << m_authorizationData; -+ return w.finalize(Packet::_Accept); -+ } -+ -+ Packet::Decline::Decline(const QHostAddress &host, quint16 port, const QString status, const QString authenticationName, const QByteArray authenticationData) : Packet(host, port), -+ m_status(status.toLatin1()), -+ m_authenticationName(authenticationName.toLatin1()), -+ m_authenticationData(authenticationData) { -+ qDebug() << " XDMCP: Prepared Decline reply for" << host << port << "with contents" << status << authenticationName << authenticationData; -+ } -+ -+ Packet::Decline::Decline(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_status >> m_authenticationName >> m_authenticationData; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::Decline::encode() const { -+ Writer w; -+ w << m_status << m_authenticationName << m_authenticationData; -+ return w.finalize(Packet::_Decline); -+ } -+ -+ Packet::Manage::Manage(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_sessionID >> m_displayNumber >> m_displayClass; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::Manage::encode() const { -+ Writer w; -+ w << m_sessionID << m_displayNumber << m_displayClass; -+ return w.finalize(Packet::_Manage); -+ } -+ -+ Packet::Refuse::Refuse(const QHostAddress &host, quint16 port, uint32_t sessionID) : Packet(host, port), -+ m_sessionID(sessionID) { -+ qDebug() << " XDMCP: Prepared Refuse reply for" << host << port << "with contents" << sessionID; -+ } -+ -+ Packet::Refuse::Refuse(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_sessionID; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::Refuse::encode() const { -+ Writer w; -+ w << m_sessionID; -+ return w.finalize(Packet::_Refuse); -+ } -+ -+ Packet::Failed::Failed(const QHostAddress &host, quint16 port, uint32_t sessionID, const QString &status) : Packet(host, port), -+ m_sessionID(sessionID), -+ m_status(status.toLatin1()) { -+ qDebug() << " XDMCP: Prepared Failed reply for" << host << port << "with contents" << sessionID << status; -+ } -+ -+ Packet::Failed::Failed(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_sessionID >> m_status; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::Failed::encode() const { -+ Writer w; -+ w << m_sessionID << m_status; -+ return w.finalize(Packet::_Failed); -+ } -+ -+ Packet::KeepAlive::KeepAlive(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_displayNumber >> m_sessionID; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::KeepAlive::encode() const { -+ Writer w; -+ w << m_displayNumber << m_sessionID; -+ return w.finalize(Packet::_KeepAlive); -+ } -+ -+ Packet::Alive::Alive(const QHostAddress &host, quint16 port, uint8_t sessionRunning, uint32_t sessionID) : Packet(host, port), -+ m_sessionRunning(sessionRunning), -+ m_sessionID(sessionID) { -+ qDebug() << " XDMCP: Prepared Alive reply for" << host << port << "with contents" << sessionRunning << sessionID; -+ } -+ -+ Packet::Alive::Alive(const QHostAddress &host, quint16 port, Reader &r) : Packet(host, port, r) { -+ r >> m_sessionRunning >> m_sessionID; -+ if (r.isFinished()) -+ m_valid = true; -+ } -+ -+ QByteArray Packet::Alive::encode() const { -+ Writer w; -+ w << m_sessionRunning << m_sessionID; -+ return w.finalize(Packet::_Alive); -+ } -+ -+/******************************************************************************* -+ * SERVER IMPLEMENTATIONS -+ ******************************************************************************/ -+ -+ Packet *Packet::Query::onServerReceived() const { -+ if (m_authenticationNames.isEmpty()) -+ return new Willing(m_host, m_port, "", Server::instance()->hostname(), Server::instance()->status()); -+ -+ return new Unwilling(m_host, m_port, Server::instance()->hostname(), "Server does not support authentication"); -+ } -+ -+ Packet* Packet::Request::onServerReceived() const { -+ qDebug() << " XDMCP: Server: Received Request" << m_displayNumber << m_connectionTypes << m_connectionAddresses << m_authenticationName << m_authenticationData << m_authorizationNames << m_manufacturerDisplayID; -+ -+ if (m_authorizationNames.contains("MIT-MAGIC-COOKIE-1")) { -+ uint32_t sessionId = Server::instance()->newSessionId(); -+ // FIXME for obvious reasons -+ QHostAddress addr(QString("%1.%2.%3.%4").arg((uint) m_connectionAddresses.first()[0]).arg((uint) m_connectionAddresses.first()[1]).arg((uint) m_connectionAddresses.first()[2]).arg((uint) m_connectionAddresses.first()[3])); -+ Display *display = Server::instance()->newDisplay(sessionId, addr.toString(), m_displayNumber); -+ -+ return new Accept(m_host, m_port, sessionId, m_authenticationName, m_authenticationData, "MIT-MAGIC-COOKIE-1", display->rawCookie()); -+ } -+ -+ return new Decline(m_host, m_port, Server::instance()->status(), m_authenticationName, m_authenticationData); -+ } -+ -+ Packet* Packet::Manage::onServerReceived() const { -+ Display *display = Server::instance()->getDisplay(m_sessionID); -+ -+ if (display != nullptr) { -+ display->start(); -+ return nullptr; // this packet doesn't have any response on success -+ } -+ -+ return new Refuse(m_host, m_port, m_sessionID); -+ } -+ -+ Packet* Packet::KeepAlive::onServerReceived() const { -+ Display *display = Server::instance()->getDisplay(m_sessionID); -+ -+ if (display == nullptr) -+ return new Alive(m_host, m_port, 0, m_sessionID); -+ -+ if (display->displayId() != m_displayNumber) -+ return new Alive(m_host, m_port, 0, m_sessionID); -+ -+ return new Alive(m_host, m_port, 1, m_sessionID); -+ } -+ -+/******************************************************************************* -+ * CLIENT IMPLEMENTATIONS -+ ******************************************************************************/ -+ -+}; -+}; -diff --git a/src/daemon/xdmcp/Packet.h b/src/daemon/xdmcp/Packet.h -new file mode 100644 -index 0000000..9246541 ---- /dev/null -+++ b/src/daemon/xdmcp/Packet.h -@@ -0,0 +1,394 @@ -+/* -+ * Packet type handling for X Display Control Protocol -+ * Copyright (C) 2013 Martin Bříza -+ * -+ * 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, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ * -+ */ -+ -+#ifndef SDDM_XDMCP_PACKET_H -+#define SDDM_XDMCP_PACKET_H -+ -+#include -+#include -+ -+#include "Utils.h" -+ -+namespace SDDM { -+namespace XDMCP { -+ class Reader; -+ /** -+ * XDMCP Packet main class -+ * -+ * Defines interface and static methods to work with the protocol data -+ */ -+ class Packet { -+ public: -+ virtual ~Packet(); -+ -+ /** -+ * Get the packet's validity (especially for responses) -+ * -+ * \return validity -+ */ -+ bool isValid() const; -+ -+ /** -+ * Defines server behavior on receiving this packet -+ */ -+ virtual Packet *onServerReceived() const; -+ -+ /** -+ * Defines client behavior on receiving this packet -+ */ -+ virtual Packet *onClientReceived() const; -+ -+ /** -+ * Encode the packet to raw data according to the protocol -+ * -+ * \return Data byte array -+ */ -+ virtual QByteArray encode() const; -+ -+ /** -+ * Decode raw packet data and create a packet for further processing -+ * -+ * \param data Raw data from the socket -+ * \param host Source host of the packet -+ * \param port Source port of the packet -+ * \return Parsed packet -+ */ -+ static Packet *decode(const QByteArray &data, const QHostAddress &host = QHostAddress(), quint16 port = 0); -+ -+ /** -+ * Set the packet's source/destination host -+ * -+ * \param host The host -+ */ -+ void setHost(const QHostAddress &host); -+ -+ /** -+ * Get the packet's source/destination host -+ * -+ * \return The host -+ */ -+ const QHostAddress& host() const; -+ -+ /** -+ * Set the packet's source/destination host -+ * -+ * \param port The port -+ */ -+ void setPort(quint16 port); -+ -+ /** -+ * Get the packet's source/destination host -+ * -+ * \return The port -+ */ -+ quint16 port() const; -+ -+ /** -+ * Redundancy for everyone! -+ */ -+ enum Opcode { -+ _None = 0, -+ _BroadcastQuery = 1, -+ _Query, -+ _IndirectQuery, -+ _ForwardQuery, -+ _Willing, -+ _Unwilling, -+ _Request, -+ _Accept, -+ _Decline, -+ _Manage, -+ _Refuse, -+ _Failed, -+ _KeepAlive, -+ _Alive, -+ }; -+ -+ class BroadcastQuery; -+ class Query; -+ class IndirectQuery; -+ class ForwardQuery; -+ class Willing; -+ class Unwilling; -+ class Request; -+ class Accept; -+ class Decline; -+ class Manage; -+ class Refuse; -+ class Failed; -+ class KeepAlive; -+ class Alive; -+ -+ protected: -+ /** -+ * C'tor targetted for creating response packets -+ * -+ * Automatically sets the packet to be valid -+ * \param host Destination host for the response -+ * \param port Destination port for the response -+ */ -+ Packet(const QHostAddress &host, quint16 port); -+ /** -+ * C'tor targetted for parsing raw data -+ * -+ * \param host Destination host for the response -+ * \param port Destination port for the response -+ * \param r Reader containing the packet's raw data -+ */ -+ Packet(const QHostAddress &host, quint16 port, Reader &r); -+ -+ QHostAddress m_host; -+ quint16 m_port { 0 }; -+ bool m_valid { false }; -+ }; -+ -+ class Packet::BroadcastQuery : public Packet { -+ public: -+ BroadcastQuery(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ private: -+ QVector m_authenticationNames; -+ }; -+ -+ class Packet::Query : public Packet { -+ public: -+ Query(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ /** -+ * Server side handling of Query packet -+ * -+ * Client sends a list of authorization names -+ * -+ * If the list is empty (and we are willing to continue without -+ * authorization), we reply with \ref Willing with empty -+ * authenticationName -+ * -+ * Otherwise, we choose the one name that complies to the supported ones -+ * in the server and use it as authenticationName for the \ref Willing -+ * packet -+ * -+ * If none of the names complies and/or we don't want to continue -+ * without authorization, the reply is \ref Unwilling -+ * -+ * \return Response -+ */ -+ virtual Packet *onServerReceived() const; -+ private: -+ QVector m_authenticationNames; -+ }; -+ -+ class Packet::IndirectQuery : public Packet { -+ public: -+ IndirectQuery(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ private: -+ QVector m_authenticationNames; -+ }; -+ -+ class Packet::ForwardQuery : public Packet { -+ public: -+ ForwardQuery(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ private: -+ QByteArray m_clientAddress; -+ QByteArray m_clientPort; -+ QVector m_authenticationNames; -+ }; -+ -+ class Packet::Willing : public Packet { -+ public: -+ Willing(const QHostAddress &host, quint16 port, -+ const QString &authenticationName, const QString &hostname, -+ const QString &status); -+ Willing(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ /** -+ * Client side handling of Willing packet -+ * -+ * Description TBD -+ * -+ * Reply on success is \ref Request -+ * -+ * \return Response -+ */ -+// virtual Packet *onClientReceived() const; -+ private: -+ QByteArray m_authenticationName; -+ QByteArray m_hostname; -+ QByteArray m_status; -+ }; -+ -+ class Packet::Unwilling : public Packet { -+ public: -+ Unwilling(const QHostAddress &host, quint16 port, -+ const QString &hostname, const QString &status); -+ Unwilling(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ private: -+ QByteArray m_hostname; -+ QByteArray m_status; -+ }; -+ -+ class Packet::Request : public Packet { -+ public: -+ Request(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ /** -+ * Server side handling of Request packet -+ * -+ * Client informs there will be displey displayNumber running on -+ * connectionAddresses accessible via connectionTypes. -+ * It also authorizes with the authenticationName and authenticationData. -+ * It sends a list of propsed authorizationNames for the server to choose -+ * one of them and reply using the \ref Accept packet where the chosen -+ * authorizationName will be stored along with the authorizationData for -+ * the client and the new sessionID. -+ * -+ * If the display cannot be used, the server replies using the \ref Decline -+ * packet with its status. -+ * -+ * \return Response -+ */ -+ virtual Packet *onServerReceived() const; -+ private: -+ uint16_t m_displayNumber; -+ QVector m_connectionTypes; -+ QVector m_connectionAddresses; -+ QByteArray m_authenticationName; -+ QByteArray m_authenticationData; -+ QVector m_authorizationNames; -+ QByteArray m_manufacturerDisplayID; -+ }; -+ -+ class Packet::Accept : public Packet { -+ public: -+ Accept(const QHostAddress &host, quint16 port, uint32_t sessionId, -+ const QString authenticationName, const QByteArray authenticationData, -+ const QString authorizationName, const QByteArray authorizationData); -+ Accept(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ /** -+ * Client side handling of Accept packet -+ * -+ * Description TBD -+ * -+ * Reply on succes is \ref Manage -+ * -+ * \return Response -+ */ -+// virtual Packet *onClientReceived() const; -+ private: -+ uint32_t m_sessionID; -+ QByteArray m_authenticationName; -+ QByteArray m_authenticationData; -+ QByteArray m_authorizationName; -+ QByteArray m_authorizationData; -+ }; -+ -+ class Packet::Decline : public Packet { -+ public: -+ Decline(const QHostAddress &host, quint16 port, const QString status, -+ const QString authenticationName, const QByteArray authenticationData); -+ Decline(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ private: -+ QByteArray m_status; -+ QByteArray m_authenticationName; -+ QByteArray m_authenticationData; -+ }; -+ -+ class Packet::Manage : public Packet { -+ public: -+ Manage(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ /** -+ * Server side handling of Manage packet -+ * -+ * Client asks the server to open a connection to its opened display -+ * specified in the previous Request packet. -+ * -+ * There is no answer on success, just opening a connection. -+ * -+ * If the connection is specified wrong (erroneous sessionID, etc.), then -+ * the server replies with a \ref Refuse packet. -+ * -+ * If the connection cannot be opened due to an internal error, -+ * \ref Failed packet is sent to the client. -+ * -+ * \return Response -+ */ -+ virtual Packet *onServerReceived() const; -+ private: -+ uint32_t m_sessionID; -+ uint16_t m_displayNumber; -+ QByteArray m_displayClass; -+ }; -+ -+ class Packet::Refuse : public Packet { -+ public: -+ Refuse(const QHostAddress &host, quint16 port, uint32_t sessionID); -+ Refuse(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ private: -+ uint32_t m_sessionID; -+ }; -+ -+ class Packet::Failed : public Packet { -+ public: -+ Failed(const QHostAddress &host, quint16 port, uint32_t sessionID, const QString &status); -+ Failed(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ private: -+ uint32_t m_sessionID; -+ QByteArray m_status; -+ }; -+ -+ class Packet::KeepAlive : public Packet { -+ public: -+ KeepAlive(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ /** -+ * Server side handling of KeepAlive packet -+ * -+ * Clients asks the server if the session is still alive. -+ * -+ * Server replies with \ref Alive packet with either sessionRunning == 0 -+ * for a dead session or sessionRunning != 0 for a live one -+ */ -+ virtual Packet *onServerReceived() const; -+ private: -+ uint16_t m_displayNumber; -+ uint32_t m_sessionID; -+ }; -+ -+ class Packet::Alive : public Packet { -+ public: -+ Alive(const QHostAddress &host, quint16 port, uint8_t sessionRunning, uint32_t sessionID); -+ Alive(const QHostAddress &host, quint16 port, Reader &r); -+ virtual QByteArray encode() const; -+ private: -+ uint8_t m_sessionRunning; -+ uint32_t m_sessionID; -+ }; -+ -+} // namespace XDMCP -+} // namespace SDDM -+ -+#endif // SDDM_XDMCP_PACKET_H -diff --git a/src/daemon/xdmcp/Server.cpp b/src/daemon/xdmcp/Server.cpp -new file mode 100644 -index 0000000..b4dc6e1 ---- /dev/null -+++ b/src/daemon/xdmcp/Server.cpp -@@ -0,0 +1,148 @@ -+/* -+ * Server implementation for X Display Control Protocol -+ * Copyright (C) 2013 Martin Bříza -+ * -+ * 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, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ * -+ */ -+ -+#include "Server.h" -+#include "Packet.h" -+#include "../DaemonApp.h" -+#include "../Display.h" -+ -+#include -+ -+namespace SDDM { -+namespace XDMCP { -+ -+ Server *Server::self = nullptr; -+ -+ Server* Server::instance(DaemonApp* parent) { -+ if (self == nullptr) { -+ self = new Server(parent); -+ } -+ return self; -+ } -+ -+ Server::Server(DaemonApp* parent) : QUdpSocket(parent), -+ m_hostname(QHostInfo::localHostName()) { -+ -+ } -+ -+ Server::~Server() { -+ -+ } -+ -+ bool Server::start() { -+ qDebug() << " XDMCP: Server: Starting..."; -+ connect(this, SIGNAL(readyRead()), this, SLOT(newData())); -+ bool result = bind(m_address, m_port); -+ if (!result) { -+ qDebug() << " XDMCP: Server: Cannot bind" << m_address << m_port << errorString(); -+ } -+ else { -+ m_started = true; -+ m_status = "online"; -+ qDebug() << " XDMCP: Server: Started and listening on" << m_address << ":" << m_port; -+ } -+ return result; -+ } -+ -+ void Server::socketError(QAbstractSocket::SocketError socketError) { -+ qDebug() << " XDMCP: Error:" << errorString(); -+ // TODO: error recovery -+ m_started = false; -+ m_status = "error"; -+ } -+ -+ QString Server::hostname() const { -+ return m_hostname; -+ } -+ -+ QString Server::status() const { -+ return m_status; -+ } -+ -+ bool Server::isStarted() const { -+ return m_started; -+ } -+ -+ uint32_t Server::newSessionId() { -+ // realistically, can this serve more than 4 billion clients to actually cause trouble in removeDisplay? -+ while (m_displays.keys().contains(m_lastSession)) -+ m_lastSession++; -+ return m_lastSession++; -+ } -+ -+ Display* Server::newDisplay(uint32_t sessionId, const QString &hostName, uint32_t displayNumber) { -+ if (m_displays.contains(sessionId)) -+ return nullptr; -+ Display *display = new Display(hostName, displayNumber, this); -+ connect(display, SIGNAL(destroyed(QObject*)), SLOT(removeDisplay(QObject*))); -+ m_displays[sessionId] = display; -+ return display; -+ } -+ -+ Display* Server::getDisplay(uint32_t id) { -+ if (m_displays.contains(id)) -+ return m_displays[id]; -+ return nullptr; -+ } -+ -+ void Server::removeDisplay(QObject* obj) { -+ int key = m_displays.key(qobject_cast(obj), -1); -+ -+ if (key == -1) -+ return; -+ -+ m_displays.remove(key); -+ } -+ -+ void Server::setAddress(QHostAddress address) { -+ m_address = address; -+ } -+ -+ void Server::setPort(int port) { -+ m_port = port; -+ } -+ -+ void Server::newData() { -+ while (hasPendingDatagrams()) { -+ QByteArray data; -+ QHostAddress sender; -+ quint16 port; -+ data.resize(pendingDatagramSize()); -+ -+ readDatagram(data.data(), data.size(), &sender, &port); -+ -+ Packet *toProcess = Packet::decode(data, sender, port); -+ if (toProcess && toProcess->isValid()) { -+ Packet *response = toProcess->onServerReceived(); -+ if (response && response->isValid()) { -+ writeDatagram(response->encode(), response->host(), response->port()); -+ } -+ delete response; -+ } else { -+ qDebug() << " XDMCP: Server: Received packet wasn't decoded as valid"; -+ } -+ delete toProcess; -+ } -+ } -+ -+} // namespace XDMCP -+} // namespace SDDM -+ -+#include "Server.moc" -diff --git a/src/daemon/xdmcp/Server.h b/src/daemon/xdmcp/Server.h -new file mode 100644 -index 0000000..6f7bdae ---- /dev/null -+++ b/src/daemon/xdmcp/Server.h -@@ -0,0 +1,118 @@ -+/* -+ * Server implementation for X Display Control Protocol -+ * Copyright (C) 2013 Martin Bříza -+ * -+ * 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, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ * -+ */ -+ -+#ifndef SDDM_XDMCP_SERVER_H -+#define SDDM_XDMCP_SERVER_H -+ -+#include -+#include -+#include -+#include -+ -+// the same as in -+#define XDM_UDP_PORT 177 -+ -+namespace SDDM { -+ -+class Display; -+ class DaemonApp; -+namespace XDMCP { -+ -+ class Server : protected QUdpSocket -+ { -+ Q_OBJECT -+ public: -+ /** -+ * Get an instance of the XDMCP server. If there isn't any, construct a -+ * new one -+ * -+ * \param parent Parent for the eventual construction -+ * \return Singleton XDMCP Server instance -+ */ -+ static Server *instance(DaemonApp *parent = nullptr); -+ /** -+ * D'tor -+ */ -+ virtual ~Server(); -+ -+ /** -+ * Set port to listen on -+ * -+ * \param port The port -+ */ -+ void setPort(int port); -+ -+ /** -+ * Set address to listen on -+ * -+ * \param address The address -+ */ -+ void setAddress(QHostAddress address); -+ -+ /** -+ * Start the server -+ * -+ * \return True if successful -+ */ -+ bool start(); -+ -+ /** -+ * Get server online status -+ * -+ * \return True if running -+ */ -+ bool isStarted() const; -+ -+ -+ /** -+ * Returns a new session ID for incoming requests -+ */ -+ uint32_t newSessionId(); -+ -+ /** -+ * Create a new display -+ */ -+ Display *newDisplay(uint32_t sessionId, const QString &hostName, uint32_t displayNumber); -+ Display *getDisplay(uint32_t id); -+ QString status() const; -+ QString hostname() const; -+ -+ private slots: -+ void newData(); -+ void socketError(QAbstractSocket::SocketError socketError); -+ void removeDisplay(QObject *obj); -+ -+ private: -+ static Server *self; -+ explicit Server(DaemonApp *parent = nullptr); -+ -+ QString m_status { "offline" }; -+ QString m_hostname { "localhost" }; -+ QHostAddress m_address { QHostAddress::Any }; -+ quint16 m_port { XDM_UDP_PORT }; -+ bool m_started { false }; -+ uint32_t m_lastSession { 0 }; -+ QMap m_displays; -+ QMap m_timers; -+ }; -+} -+} -+ -+#endif // SDDM_XDMCP_SERVER_H -diff --git a/src/daemon/xdmcp/Utils.cpp b/src/daemon/xdmcp/Utils.cpp -new file mode 100644 -index 0000000..53ac7e3 ---- /dev/null -+++ b/src/daemon/xdmcp/Utils.cpp -@@ -0,0 +1,143 @@ -+/* -+ * Utilities for X Display Control Protocol -+ * Copyright (C) 2013 Martin Bříza -+ * -+ * 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, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ * -+ */ -+ -+#include "Utils.h" -+ -+#include -+ -+namespace SDDM { -+namespace XDMCP { -+ -+ Reader::Reader(const QByteArray &data) : m_data(data), -+ m_stream(&m_data, QIODevice::ReadOnly | QIODevice::Unbuffered) { -+ m_stream.setByteOrder(QDataStream::BigEndian); -+ } -+ -+ Reader& Reader::operator>>(uint8_t &byte) { -+ m_stream >> byte; -+ return *this; -+ } -+ -+ Reader& Reader::operator>>(uint16_t &word) { -+ m_stream >> word; -+ return *this; -+ } -+ -+ Reader& Reader::operator>>(uint32_t &doubleword) { -+ m_stream >> doubleword; -+ return *this; -+ } -+ -+ Reader& Reader::operator>>(QByteArray &array) { -+ uint16_t arrayLen; -+ *this >> arrayLen; -+ while (arrayLen--) { -+ uint8_t byte; -+ *this >> byte; -+ array.append(byte); -+ } -+ return *this; -+ } -+ -+ Reader& Reader::operator>>(QVector< uint16_t > &wordArray) { -+ uint8_t arrayLen; -+ *this >> arrayLen; -+ while (arrayLen--) { -+ uint16_t word; -+ *this >> word; -+ wordArray.append(word); -+ } -+ return *this; -+ } -+ -+ Reader& Reader::operator>>(QVector< QByteArray > &arrayOfArrays) { -+ uint8_t arrayCount; -+ *this >> arrayCount; -+ while (arrayCount--) { -+ QByteArray array; -+ *this >> array; -+ arrayOfArrays.append(array); -+ } -+ return *this; -+ } -+ -+ bool Reader::isFinished() const { -+ if ((m_stream.status() == QDataStream::Ok) && m_stream.atEnd()) -+ return true; -+ else -+ return false; -+ } -+ -+ Writer::Writer() : m_data(), -+ m_stream(&m_data, QIODevice::WriteOnly | QIODevice::Unbuffered) { -+ m_stream.setByteOrder(QDataStream::BigEndian); -+ } -+ -+ Writer& Writer::operator<<(const uint8_t byte) { -+ qDebug() << "Appending:" << byte << QChar(byte); -+ m_stream << byte; -+ return *this; -+ } -+ -+ Writer& Writer::operator<<(const uint16_t word) { -+ m_stream << word; -+ return *this; -+ } -+ -+ Writer& Writer::operator<<(const uint32_t doubleword) { -+ m_stream << doubleword; -+ return *this; -+ } -+ -+ Writer& Writer::operator<<(const QByteArray &array) { -+ *this << (uint16_t) array.count(); -+ for (uint8_t c : array) -+ m_stream << c; -+ return *this; -+ } -+ -+ Writer& Writer::operator<<(const QVector< uint16_t > &wordArray) { -+ *this << (uint8_t) wordArray.count(); -+ for (const uint16_t &i : wordArray) -+ *this << i; -+ return *this; -+ } -+ -+ Writer& Writer::operator<<(const QVector< QByteArray > &arrayOfArrays) { -+ *this << (uint16_t) arrayOfArrays.count(); -+ for (const QByteArray &i : arrayOfArrays) -+ *this << i; -+ return *this; -+ } -+ -+ QByteArray Writer::finalize(uint16_t opcode) { -+ QByteArray result; -+ QDataStream finalStream(&result, QIODevice::WriteOnly | QIODevice::Unbuffered); -+ finalStream.setByteOrder(QDataStream::BigEndian); -+ finalStream << (uint16_t) 1; -+ finalStream << (uint16_t) opcode; -+ finalStream << (uint16_t) m_data.size(); -+ for (uint8_t c : m_data) -+ finalStream << c; -+ return result; -+ } -+ -+} // namespace XDMCP -+} // namespace SDDM -\ No newline at end of file -diff --git a/src/daemon/xdmcp/Utils.h b/src/daemon/xdmcp/Utils.h -new file mode 100644 -index 0000000..bd96708 ---- /dev/null -+++ b/src/daemon/xdmcp/Utils.h -@@ -0,0 +1,93 @@ -+/* -+ * Utilities for X Display Control Protocol -+ * Copyright (C) 2013 Martin Bříza -+ * -+ * 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, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ * -+ */ -+ -+#ifndef SDDM_XDMCP_UTILS_H -+#define SDDM_XDMCP_UTILS_H -+ -+#include -+#include -+ -+#include "Packet.h" -+ -+namespace SDDM { -+namespace XDMCP { -+ -+ /** -+ * Class for reading information from raw packets and setting the right byte order -+ * -+ * Workflow is as follows: -+ * * Construct Reader from the data received -+ * * Using the stream operator extract all required variables -+ * * Check if the stream is at its end by isFinished() -+ */ -+ class Reader { -+ public: -+ Reader(const QByteArray &data); -+ ~Reader() {} -+ Reader& operator>>(uint8_t &byte); -+ Reader& operator>>(uint16_t &word); -+ Reader& operator>>(uint32_t &doubleword); -+ Reader& operator>>(QByteArray &array); -+ Reader& operator>>(QVector &wordArray); -+ Reader& operator>>(QVector &arrayOfArrays); -+ /** -+ * Returns true if the stream is at its end and no errors occured -+ * -+ * \return Finished status -+ */ -+ bool isFinished() const; -+ private: -+ QByteArray m_data; -+ QDataStream m_stream; -+ }; -+ -+ /** -+ * Class for writing information to raw packets and setting the right byte order -+ * -+ * Workflow is as follows: -+ * * Construct empty writer -+ * * Using the stream operator insert all contained variables -+ * * Get a complete packet by the finalize(opcode) method -+ */ -+ class Writer { -+ public: -+ Writer(); -+ Writer& operator<<(const uint8_t byte); -+ Writer& operator<<(const uint16_t word); -+ Writer& operator<<(const uint32_t doubleword); -+ Writer& operator<<(const QByteArray &array); -+ Writer& operator<<(const QVector &wordArray); -+ Writer& operator<<(const QVector &arrayOfArrays); -+ /** -+ * Finalizes building of the packet -+ * -+ * \param opcode XDMCP protocol code of the packet type -+ * \return Raw packet data -+ */ -+ QByteArray finalize(uint16_t opcode); -+ private: -+ QByteArray m_data; -+ QDataStream m_stream; -+ }; -+ -+} // namespace XDMCP -+} // namespace SDDM -+ -+#endif // SDDM_XDMCP_UTILS_H diff --git a/sddm-autologin.pam b/sddm-autologin.pam new file mode 100644 index 0000000..0616e66 --- /dev/null +++ b/sddm-autologin.pam @@ -0,0 +1,16 @@ + #%PAM-1.0 +auth required pam_env.so +auth required pam_permit.so +auth include postlogin +account required pam_nologin.so +account include system-auth +password include system-auth +session required pam_selinux.so close +session required pam_loginuid.so +session optional pam_console.so +-session optional pam_ck_connector.so +session required pam_selinux.so open +session optional pam_keyinit.so force revoke +session required pam_namespace.so +session include system-auth +session include postlogin diff --git a/sddm-git.e707e229-session-list.patch b/sddm-git.e707e229-session-list.patch deleted file mode 100644 index d884413..0000000 --- a/sddm-git.e707e229-session-list.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/src/greeter/SessionModel.cpp b/src/greeter/SessionModel.cpp -index 8c232ba..8269c4c 100644 ---- a/src/greeter/SessionModel.cpp -+++ b/src/greeter/SessionModel.cpp -@@ -56,9 +56,6 @@ namespace SDDM { - // set role names - setRoleNames(roleNames); - #endif -- // add custom and failsafe session -- d->sessions << SessionPtr { new Session {"custom", "Custom", "custom", "Custom Session"} }; -- d->sessions << SessionPtr { new Session {"failsafe", "Failsafe", "failsafe", "Failsafe Session"} }; - // read session files - QDir dir(Configuration::instance()->sessionsDir()); - dir.setNameFilters(QStringList() << "*.desktop"); -@@ -84,6 +81,10 @@ namespace SDDM { - // close file - inputFile.close(); - } -+ // add custom and failsafe session -+// hidden for now --mbriza -+// d->sessions << SessionPtr { new Session {"custom", "Custom", "custom", "Custom Session"} }; -+ d->sessions << SessionPtr { new Session {"failsafe", "Failsafe", "failsafe", "Failsafe Session"} }; - // find out index of the last session - for (int i = 0; i < d->sessions.size(); ++i) { - if (d->sessions.at(i)->file == Configuration::instance()->lastSession()) diff --git a/sddm-pam_end.patch b/sddm-pam_end.patch deleted file mode 100644 index f9f9391..0000000 --- a/sddm-pam_end.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- sddm-7a008602f5f0a4ed8586ce24012983458a687d4e/src/daemon/Authenticator.cpp.pam_end 2013-12-16 15:26:35.749298583 +0100 -+++ sddm-7a008602f5f0a4ed8586ce24012983458a687d4e/src/daemon/Authenticator.cpp 2013-12-16 15:26:45.273274332 +0100 -@@ -418,10 +418,9 @@ namespace SDDM { - if (m_pam) { - m_pam->result = pam_close_session(m_pam->handle, 0); - m_pam->result = pam_setcred(m_pam->handle, PAM_DELETE_CRED); -- // for some reason this has to be called here too -- pam_end(m_pam->handle, m_pam->result); - delete m_pam; - m_pam = nullptr; -+ daemonApp->exit(0); // until PAM is fixed, we have to restart the whole service with audit - } - #endif - \ No newline at end of file diff --git a/sddm.spec b/sddm.spec index 61f6cc6..5ccd448 100644 --- a/sddm.spec +++ b/sddm.spec @@ -1,9 +1,9 @@ %global _hardened_build 1 -%global sddm_commit 7a008602f5f0a4ed8586ce24012983458a687d4e +%global sddm_commit db1d7381754a01a69b0f4c579c0267d80183c066 Name: sddm Version: 0.2.0 -Release: 0.26.20131125git%(echo %{sddm_commit} | cut -c-8)%{?dist} +Release: 0.27.20131125git%(echo %{sddm_commit} | cut -c-8)%{?dist} # code GPLv2+, fedora theme CC-BY-SA License: GPLv2+ and CC-BY-SA Summary: QML based X11 desktop manager @@ -13,25 +13,20 @@ Source0: https://github.com/MartinBriza/sddm/archive/%{sddm_commit}.tar.g # fedora standard sddm.conf Source10: sddm.conf -# Originally kdm config, shamelessly stolen from gdm +# Shamelessly stolen from gdm Source11: sddm.pam +# Shamelessly stolen from gdm +Source12: sddm-autologin.pam # We need to ship our own service file to handle Fedora-specific cases -Source12: sddm.service +Source13: sddm.service # systesmd tmpfiles support for /var/run/sddm -Source13: tmpfiles-sddm.conf +Source14: tmpfiles-sddm.conf # fedora theme files Source21: fedora-Main.qml Source22: fedora-metadata.desktop Source23: fedora-theme.conf -# Patch setting a better order of the xsessions and hiding the custom one -Patch2: sddm-git.e707e229-session-list.patch - -Patch3: sddm-0.2.0-0.11.20130914git50ca5b20-xdmcp.patch -# Don't end the PAM session twice -Patch4: sddm-pam_end.patch - Provides: service(graphical-login) = sddm BuildRequires: cmake @@ -50,8 +45,11 @@ Requires: system-logos Requires: systemd Requires: xorg-x11-xinit Requires: xorg-x11-server-Xorg +Requires: %{name}-helper %{?systemd_requires} +Requires(pre): shadow-utils + %description SDDM is a modern display manager for X11 aiming to be fast, simple and beautiful. It uses modern technologies like QtQuick, which in turn gives the @@ -70,13 +68,6 @@ A collection of sddm themes, including: circles, elarun, maldives, maui. %prep %setup -q -n %{name}-%{sddm_commit} -%patch2 -p1 -b .session-list -%patch3 -p1 -b .xdmcp -%patch4 -p1 -b .pam_end - -# get rid of the architecture flag -sed -i "s/-march=native//" CMakeLists.txt - %build mkdir -p %{_target_platform} @@ -92,15 +83,23 @@ make install/fast DESTDIR=%{buildroot} -C %{_target_platform} install -Dpm 644 %{SOURCE10} %{buildroot}%{_sysconfdir}/sddm.conf install -Dpm 644 %{SOURCE11} %{buildroot}%{_sysconfdir}/pam.d/sddm -install -Dpm 644 %{SOURCE12} %{buildroot}%{_unitdir}/sddm.service -install -Dpm 644 %{SOURCE13} %{buildroot}%{_tmpfilesdir}/sddm.conf +install -Dpm 644 %{SOURCE12} %{buildroot}%{_sysconfdir}/pam.d/sddm-autologin +install -Dpm 644 %{SOURCE13} %{buildroot}%{_unitdir}/sddm.service +install -Dpm 644 %{SOURCE14} %{buildroot}%{_tmpfilesdir}/sddm.conf mkdir -p %{buildroot}%{_localstatedir}/run/sddm # install fedora theme -install -Dpm 644 %{SOURCE21} %{buildroot}%{_datadir}/apps/sddm/themes/fedora/Main.qml -install -Dpm 644 %{SOURCE22} %{buildroot}%{_datadir}/apps/sddm/themes/fedora/metadata.desktop -install -Dpm 644 %{SOURCE23} %{buildroot}%{_datadir}/apps/sddm/themes/fedora/theme.conf +install -Dpm 644 %{SOURCE21} %{buildroot}%{_datadir}/sddm/themes/fedora/Main.qml +install -Dpm 644 %{SOURCE22} %{buildroot}%{_datadir}/sddm/themes/fedora/metadata.desktop +install -Dpm 644 %{SOURCE23} %{buildroot}%{_datadir}/sddm/themes/fedora/theme.conf + +%pre +getent group sddm >/dev/null || groupadd -r sddm +getent passwd sddm >/dev/null || \ + useradd -r -g sddm -d /var/lib/sddm -s /sbin/nologin \ + -c "Simple Desktop Display Manager" sddm +exit 0 %post %systemd_post sddm.service @@ -109,15 +108,18 @@ install -Dpm 644 %{SOURCE23} %{buildroot}%{_datadir}/apps/sddm/themes/fedora/the %systemd_preun sddm.service %postun -%systemd_postun sddm.service +%systemd_postun sddm.service %files %doc COPYING README.md CONTRIBUTORS %config %{_sysconfdir}/sddm.conf %config(noreplace) %{_sysconfdir}/pam.d/sddm +%config(noreplace) %{_sysconfdir}/pam.d/sddm-autologin +%config(noreplace) %{_sysconfdir}/pam.d/sddm-greeter %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.DisplayManager.conf %{_bindir}/sddm %{_bindir}/sddm-greeter +%{_libexecdir}/sddm-helper %{_tmpfilesdir}/sddm.conf %attr(0711,root,root) %dir %{_localstatedir}/run/sddm %{_unitdir}/sddm.service @@ -125,23 +127,28 @@ install -Dpm 644 %{SOURCE23} %{buildroot}%{_datadir}/apps/sddm/themes/fedora/the # or add Requires: kde-filesystem -- rex %dir %{_datadir}/apps %dir %{_datadir}/apps/sddm -%{_datadir}/apps/sddm/faces/ -%{_datadir}/apps/sddm/flags/ -%{_datadir}/apps/sddm/scripts/ -%{_datadir}/apps/sddm/sddm.conf.sample +%{_datadir}/sddm/faces/ +%{_datadir}/sddm/flags/ +%{_datadir}/sddm/scripts/ +%{_datadir}/sddm/sddm.conf.sample %dir %{_datadir}/apps/sddm/themes/ # default fedora theme -%{_datadir}/apps/sddm/themes/fedora/ +%{_datadir}/sddm/themes/fedora/ # %%lang'ify ? -- rex -%{_datadir}/apps/sddm/translations/ +%{_datadir}/sddm/translations/ %files themes -%{_datadir}/apps/sddm/themes/circles/ -%{_datadir}/apps/sddm/themes/elarun/ -%{_datadir}/apps/sddm/themes/maldives/ -%{_datadir}/apps/sddm/themes/maui/ +%{_datadir}/sddm/themes/circles/ +%{_datadir}/sddm/themes/elarun/ +%{_datadir}/sddm/themes/maldives/ +%{_datadir}/sddm/themes/maui/ %changelog +* Sun Jun 08 2014 Fedora Release Engineering - 0.2.0-0.27.20131125gitdb1d7381 +- Updated to the latest upstream git +- Notable changes: Greeter runs under the sddm user, it's possible to configure display setup, different install paths in /usr/share +- Resolves: #1034414 #1035939 #1035950 #1036308 #1038548 #1045722 #1045937 #1065715 #1082229 #1007067 #1027711 #1031745 #1008951 #1016902 #1031415 #1020921 + * Sun Jun 08 2014 Fedora Release Engineering - 0.2.0-0.26.20131125git7a008602 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild diff --git a/sources b/sources index 3f82cbc..51d0e01 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -23b2a10ad2a2f188c9a2cc4bcd35c275 7a008602f5f0a4ed8586ce24012983458a687d4e.tar.gz +eeb5bc6c493b018f73482de460b29f78 db1d7381754a01a69b0f4c579c0267d80183c066.tar.gz