Sophie

Sophie

distrib > Fedora > 18 > x86_64 > by-pkgid > 14004fd9b50371f559f10568a851c5ef > files > 5

sddm-0.2.0-0.16.20130914git50ca5b20.fc18.src.rpm

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 c40cdea..616282e 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 8517124..80aa95a 100644
--- a/src/daemon/Display.cpp
+++ b/src/daemon/Display.cpp
@@ -53,6 +53,19 @@ 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, QObject *parent) : QObject(parent),
         m_displayId(displayId), m_terminalId(terminalId),
         m_authenticator(new Authenticator(this)),
@@ -62,12 +75,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)));
 
@@ -90,6 +108,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() {
@@ -112,6 +146,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;
+    }
+
     void Display::addCookie(const QString &file) {
         // log message
         qDebug() << " DAEMON: Adding cookie to" << file;
@@ -139,28 +183,14 @@ namespace SDDM {
         if (m_started)
             return;
 
-        // generate cookie
-        std::random_device rd;
-        std::mt19937 gen(rd());
-        std::uniform_int_distribution<> dis(0, 15);
-
-        // resever 32 bytes
-        m_cookie.reserve(32);
+        if (m_displayServer != nullptr) {
+            // set display server params
+            m_displayServer->setDisplay(m_display);
+            m_displayServer->setAuthPath(m_authPath);
 
-        // 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()) {
@@ -216,9 +246,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 9d82678..9c475a9 100644
--- a/src/daemon/Display.h
+++ b/src/daemon/Display.h
@@ -34,6 +34,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, QObject *parent = 0);
         ~Display();
 
@@ -43,6 +44,7 @@ namespace SDDM {
         const QString &name() const;
 
         const QString &cookie() const;
+        const QByteArray rawCookie() const;
         void addCookie(const QString &file);
 
     public slots:
@@ -58,6 +60,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..90688d0
--- /dev/null
+++ b/src/daemon/xdmcp/Packet.cpp
@@ -0,0 +1,435 @@
+/*
+ * Packet type handling for X Display Control Protocol
+ * Copyright (C) 2013  Martin Bříza <mbriza@redhat.com>
+ *
+ * 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);
+    }
+
+    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());
+        }
+        else {
+            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();
+            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());
+        } else {
+            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;
+        } else {
+            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);
+        else if (display->displayId() != m_displayNumber)
+            return new Alive(m_host, m_port, 0, m_sessionID);
+        else {
+            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..507b1b4
--- /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 <mbriza@redhat.com>
+ *
+ * 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 <QtCore/QByteArray>
+#include <QtNetwork/QHostAddress>
+
+#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
+         */
+        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<QByteArray> 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<QByteArray> m_authenticationNames;
+    };
+
+    class Packet::IndirectQuery : public Packet {
+    public:
+        IndirectQuery(const QHostAddress& host, quint16 port, Reader& r);
+        virtual QByteArray encode() const;
+    private:
+        QVector<QByteArray> 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<QByteArray> 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<uint16_t> m_connectionTypes;
+        QVector<QByteArray> m_connectionAddresses;
+        QByteArray m_authenticationName;
+        QByteArray m_authenticationData;
+        QVector<QByteArray> 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..edfdff4
--- /dev/null
+++ b/src/daemon/xdmcp/Server.cpp
@@ -0,0 +1,149 @@
+/*
+ * Server implementation for X Display Control Protocol
+ * Copyright (C) 2013  Martin Bříza <mbriza@redhat.com>
+ *
+ * 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 <QtNetwork/QHostInfo>
+
+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, 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];
+        else
+            return nullptr;
+    }
+
+    void Server::removeDisplay(QObject* obj) {
+        int key = m_displays.key(qobject_cast<Display*>(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..2898381
--- /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 <mbriza@redhat.com>
+ *
+ * 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 <QtCore/QObject>
+#include <QtCore/QMap>
+#include <QtCore/QTimer>
+#include <QtNetwork/QUdpSocket>
+
+// the same as in <X11/Xdmcp.h>
+#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, 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<int, Display*> m_displays;
+        QMap<int, QTimer*> 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..92e1d6a
--- /dev/null
+++ b/src/daemon/xdmcp/Utils.cpp
@@ -0,0 +1,145 @@
+/*
+ * Utilities for X Display Control Protocol
+ * Copyright (C) 2013  Martin Bříza <mbriza@redhat.com>
+ *
+ * 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 <QtCore/QVector>
+
+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..9457ef1
--- /dev/null
+++ b/src/daemon/xdmcp/Utils.h
@@ -0,0 +1,93 @@
+/*
+ * Utilities for X Display Control Protocol
+ * Copyright (C) 2013  Martin Bříza <mbriza@redhat.com>
+ *
+ * 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 <QtCore/QByteArray>
+#include <QtCore/QDataStream>
+
+#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<uint16_t>& wordArray);
+            Reader& operator>>(QVector<QByteArray>& 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<uint16_t>& wordArray);
+            Writer& operator<<(const QVector<QByteArray>& 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