You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3898 lines
124 KiB
3898 lines
124 KiB
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
|
|
index 1d6d117..e1c4b4b 100644
|
|
--- a/src/CMakeLists.txt
|
|
+++ b/src/CMakeLists.txt
|
|
@@ -17,12 +17,8 @@ set(DAEMON_SOURCES
|
|
daemon/PowerManager.cpp
|
|
daemon/Seat.cpp
|
|
daemon/SeatManager.cpp
|
|
- daemon/Session.cpp
|
|
daemon/SignalHandler.cpp
|
|
daemon/SocketServer.cpp
|
|
- daemon/xdmcp/Packet.cpp
|
|
- daemon/xdmcp/Server.cpp
|
|
- daemon/xdmcp/Utils.cpp
|
|
)
|
|
|
|
if(USE_QT5)
|
|
@@ -32,11 +28,6 @@ if(USE_QT5)
|
|
|
|
add_executable(sddm ${DAEMON_SOURCES})
|
|
target_link_libraries(sddm ${LIBXCB_LIBRARIES})
|
|
- if(PAM_FOUND)
|
|
- target_link_libraries(sddm ${PAM_LIBRARIES})
|
|
- else()
|
|
- target_link_libraries(sddm crypt)
|
|
- endif()
|
|
qt5_use_modules(sddm DBus Network)
|
|
else()
|
|
set(QT_USE_QTNETWORK TRUE)
|
|
@@ -58,6 +49,43 @@ endif()
|
|
|
|
install(TARGETS sddm DESTINATION ${BIN_INSTALL_DIR})
|
|
|
|
+## AUTHENTICATOR ##
|
|
+
|
|
+set(AUTHENTICATOR_SOURCES
|
|
+ auth/AuthenticatorApp.cpp
|
|
+ auth/Method.cpp
|
|
+ auth/Session.cpp
|
|
+ common/Configuration.cpp
|
|
+)
|
|
+if(PAM_FOUND)
|
|
+ set(AUTHENTICATOR_SOURCES
|
|
+ ${AUTHENTICATOR_SOURCES}
|
|
+ auth/PAM.cpp
|
|
+ )
|
|
+endif()
|
|
+
|
|
+if(USE_QT5)
|
|
+ add_executable(sddm-auth ${AUTHENTICATOR_SOURCES})
|
|
+ target_link_libraries(sddm-auth ${LIBXCB_LIBRARIES})
|
|
+ if(PAM_FOUND)
|
|
+ target_link_libraries(sddm-auth ${PAM_LIBRARIES})
|
|
+ else()
|
|
+ target_link_libraries(sddm-auth crypt)
|
|
+ endif()
|
|
+else()
|
|
+ include(${QT_USE_FILE})
|
|
+
|
|
+ add_executable(sddm-auth ${AUTHENTICATOR_SOURCES})
|
|
+ target_link_libraries(sddm-auth ${LIBXCB_LIBRARIES} ${QT_LIBRARIES})
|
|
+ if(PAM_FOUND)
|
|
+ target_link_libraries(sddm-auth ${PAM_LIBRARIES})
|
|
+ else()
|
|
+ target_link_libraries(sddm-auth crypt)
|
|
+ endif()
|
|
+endif()
|
|
+
|
|
+install(TARGETS sddm-auth DESTINATION ${BIN_INSTALL_DIR})
|
|
+
|
|
## GREETER ##
|
|
|
|
set(GREETER_SOURCES
|
|
diff --git a/src/auth/AuthenticatorApp.cpp b/src/auth/AuthenticatorApp.cpp
|
|
new file mode 100644
|
|
index 0000000..dc4f039
|
|
--- /dev/null
|
|
+++ b/src/auth/AuthenticatorApp.cpp
|
|
@@ -0,0 +1,177 @@
|
|
+/*
|
|
+ * <one line to give the program's name and a brief idea of what it does.>
|
|
+ * Copyright (C) 2013 Martin Bříza <email>
|
|
+ *
|
|
+ * 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 "AuthenticatorApp.h"
|
|
+#include "Configuration.h"
|
|
+#include "Constants.h"
|
|
+#include "Method.h"
|
|
+#include "PAM.h"
|
|
+#include "Session.h"
|
|
+
|
|
+#include <QtCore/QDebug>
|
|
+#include <QtCore/QFile>
|
|
+#include <QtCore/qtextstream.h>
|
|
+#include <QtCore/QSocketNotifier>
|
|
+
|
|
+#include <cstdio>
|
|
+#include <iostream>
|
|
+
|
|
+namespace SDDM {
|
|
+ AuthenticatorApp *AuthenticatorApp::self = nullptr;
|
|
+
|
|
+ AuthenticatorApp::AuthenticatorApp(int argc, char **argv)
|
|
+ : QCoreApplication(argc, argv)
|
|
+ , m_method(new Method(this))
|
|
+ , m_notifier(new QSocketNotifier(fileno(stdin), QSocketNotifier::Read, this)) {
|
|
+ if (!self)
|
|
+ self = this;
|
|
+ new Configuration(CONFIG_FILE, this);
|
|
+ connect(this, SIGNAL(started(QString,QString,QString,bool)), m_method, SLOT(start(QString,QString,QString,bool)));
|
|
+ connect(this, SIGNAL(stopped()), m_method, SLOT(stop()));
|
|
+ connect(m_method, SIGNAL(loginFailed()), this, SLOT(slotLoginFailed()));
|
|
+ connect(m_method, SIGNAL(loginSucceeded(QString)), this, SLOT(slotLoginSucceeded(QString)));
|
|
+ connect(m_method, SIGNAL(sessionTerminated()), this, SLOT(quit()));
|
|
+ connect(m_notifier, SIGNAL(activated(int)), this, SLOT(readFromParent(int)));
|
|
+ m_notifier->setEnabled(true);
|
|
+
|
|
+ m_input.open(fileno(stdin), QIODevice::ReadOnly | QIODevice::Unbuffered);
|
|
+ m_output.open(fileno(stdout), QIODevice::WriteOnly | QIODevice::Unbuffered);
|
|
+
|
|
+ qCritical() << " AUTH: Started";
|
|
+ }
|
|
+
|
|
+ AuthenticatorApp* AuthenticatorApp::instance() {
|
|
+ return self;
|
|
+ }
|
|
+
|
|
+ void AuthenticatorApp::readFromParent(int fd) {
|
|
+ qDebug() << " AUTH: Message received" << m_input.bytesAvailable();
|
|
+ QDataStream inStream(&m_input);
|
|
+ quint32 command = quint32(AuthMessages::AuthNone);
|
|
+ inStream >> command;
|
|
+ qDebug() << "Command" << command;
|
|
+ handleMessage(AuthMessages(command));
|
|
+ }
|
|
+
|
|
+ void AuthenticatorApp::handleMessage(AuthMessages command) {
|
|
+ QDataStream inStream(&m_input);
|
|
+ QDataStream outStream(&m_output);
|
|
+ switch (command) {
|
|
+ case AuthMessages::Start: {
|
|
+ QString user, session, password;
|
|
+ bool passwordless;
|
|
+ inStream >> user >> session >> password >> passwordless;
|
|
+ emit started(user, session, password, passwordless);
|
|
+ break;
|
|
+ }
|
|
+ case AuthMessages::End:
|
|
+ emit stopped();
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ QProcessEnvironment AuthenticatorApp::requestEnvironment(const QString &user) {
|
|
+ qDebug() << " AUTH: requestEnvironment start";
|
|
+ QDataStream inStream(&m_input);
|
|
+ QDataStream outStream(&m_output);
|
|
+ quint32 command = quint32(AuthMessages::AuthNone);
|
|
+ int count;
|
|
+ QProcessEnvironment env;
|
|
+
|
|
+ qDebug() << "Requesting environment for user" << user;
|
|
+ outStream << quint32(AuthMessages::RequestEnv) << user;
|
|
+
|
|
+ inStream >> command;
|
|
+ if (command != quint32(AuthMessages::Env)) {
|
|
+ qDebug() << " AUTH: Received out of order message" << command << "when waiting for Env";
|
|
+ handleMessage(AuthMessages(command));
|
|
+ return env;
|
|
+ }
|
|
+
|
|
+ inStream >> count;
|
|
+ while (count--) {
|
|
+ QString entry;
|
|
+ inStream >> entry;
|
|
+ env.insert(entry.left(entry.indexOf("=")), entry.mid(entry.indexOf("=") + 1));
|
|
+ }
|
|
+
|
|
+ return env;
|
|
+ }
|
|
+
|
|
+ int AuthenticatorApp::requestSessionId() {
|
|
+ qDebug() << " AUTH: requestSessionId start";
|
|
+ QDataStream inStream(&m_input);
|
|
+ QDataStream outStream(&m_output);
|
|
+ quint32 command = quint32(AuthMessages::AuthNone);
|
|
+ int id;
|
|
+
|
|
+ outStream << quint32(AuthMessages::RequestSessionID);
|
|
+
|
|
+ inStream >> command;
|
|
+ if (command != quint32(AuthMessages::SessionID)) {
|
|
+ qDebug() << " AUTH: Received out of order message" << command << "when waiting for SessionID";
|
|
+ handleMessage(AuthMessages(command));
|
|
+ return -1;
|
|
+ }
|
|
+ inStream >> id;
|
|
+
|
|
+ qDebug() << " AUTH: requestSessionId end";
|
|
+ return id;
|
|
+ }
|
|
+
|
|
+ bool AuthenticatorApp::requestCookieTo(const QString& path, const QString &user) {
|
|
+ qDebug() << " AUTH: requestCookieTo start";
|
|
+ QDataStream inStream(&m_input);
|
|
+ QDataStream outStream(&m_output);
|
|
+ quint32 command = quint32(AuthMessages::AuthNone);
|
|
+ qDebug() << " AUTH: Requesting Cookie to path" << path << "for user" << user;
|
|
+
|
|
+ outStream << quint32(AuthMessages::RequestCookieLink) << path << user;
|
|
+
|
|
+ inStream >> command;
|
|
+ if (command != quint32(AuthMessages::CookieLink)) {
|
|
+ qDebug() << " AUTH: Received out of order message" << command << "when waiting for SessionID";
|
|
+ handleMessage(AuthMessages(command));
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ qDebug() << " AUTH: requestCookieTo end";
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ void AuthenticatorApp::slotLoginFailed() {
|
|
+ QDataStream outStream(&m_output);
|
|
+ outStream << quint32(AuthMessages::LoginFailed);
|
|
+ }
|
|
+
|
|
+ void AuthenticatorApp::slotLoginSucceeded(QString user) {
|
|
+ QDataStream outStream(&m_output);
|
|
+ outStream << quint32(AuthMessages::LoginSucceeded) << m_method->name() << user;
|
|
+ }
|
|
+}
|
|
+
|
|
+int main(int argc, char **argv) {
|
|
+ SDDM::AuthenticatorApp app(argc, argv);
|
|
+ return app.exec();
|
|
+}
|
|
+
|
|
+#include "AuthenticatorApp.moc"
|
|
diff --git a/src/auth/AuthenticatorApp.h b/src/auth/AuthenticatorApp.h
|
|
new file mode 100644
|
|
index 0000000..d0ea73b
|
|
--- /dev/null
|
|
+++ b/src/auth/AuthenticatorApp.h
|
|
@@ -0,0 +1,68 @@
|
|
+/*
|
|
+ * <one line to give the program's name and a brief idea of what it does.>
|
|
+ * Copyright (C) 2013 Martin Bříza <email>
|
|
+ *
|
|
+ * 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 AUTHENTICATORAPP_H
|
|
+#define AUTHENTICATORAPP_H
|
|
+
|
|
+#include "Messages.h"
|
|
+
|
|
+#include <QtCore/QObject>
|
|
+#include <QtCore/QCoreApplication>
|
|
+#include <QtCore/QProcess>
|
|
+#include <QtCore/QSocketNotifier>
|
|
+#include <QtCore/QFile>
|
|
+
|
|
+namespace SDDM {
|
|
+
|
|
+ class Method;
|
|
+ class AuthenticatorApp : public QCoreApplication
|
|
+ {
|
|
+ Q_OBJECT
|
|
+ public:
|
|
+ explicit AuthenticatorApp(int argc, char **argv);
|
|
+ static AuthenticatorApp *instance();
|
|
+
|
|
+ QProcessEnvironment requestEnvironment(const QString &user);
|
|
+ int requestSessionId();
|
|
+ bool requestCookieTo(const QString &path, const QString &user);
|
|
+
|
|
+ signals:
|
|
+ void started(const QString &user, const QString &session, const QString &password, bool passwordless);
|
|
+ void stopped();
|
|
+
|
|
+ public slots:
|
|
+ void slotLoginSucceeded(QString user);
|
|
+ void slotLoginFailed();
|
|
+
|
|
+ private slots:
|
|
+ void readFromParent(int fd);
|
|
+ void handleMessage(AuthMessages command);
|
|
+
|
|
+ private:
|
|
+ static AuthenticatorApp *self;
|
|
+
|
|
+ Method *m_method { nullptr };
|
|
+ QSocketNotifier *m_notifier { nullptr };
|
|
+ QFile m_input { };
|
|
+ QFile m_output { };
|
|
+ };
|
|
+}
|
|
+
|
|
+#endif // AUTHENTICATORAPP_H
|
|
diff --git a/src/auth/Method.cpp b/src/auth/Method.cpp
|
|
new file mode 100644
|
|
index 0000000..5e1c758
|
|
--- /dev/null
|
|
+++ b/src/auth/Method.cpp
|
|
@@ -0,0 +1,329 @@
|
|
+/*
|
|
+ * <one line to give the program's name and a brief idea of what it does.>
|
|
+ * Copyright (C) 2013 Martin Bříza <email>
|
|
+ *
|
|
+ * 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 "Method.h"
|
|
+#include "Configuration.h"
|
|
+#include "Session.h"
|
|
+#include "AuthenticatorApp.h"
|
|
+
|
|
+#include <QtCore/QDebug>
|
|
+#include <QtCore/QProcess>
|
|
+#include <QtCore/QDir>
|
|
+
|
|
+#ifndef USE_PAM
|
|
+#include <crypt.h>
|
|
+#include <shadow.h>
|
|
+#else
|
|
+#include "PAM.h"
|
|
+#endif
|
|
+
|
|
+#include <grp.h>
|
|
+#include <pwd.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+namespace SDDM {
|
|
+ Method::Method(QObject* parent)
|
|
+ : QObject(parent) {
|
|
+
|
|
+ }
|
|
+
|
|
+ QString Method::name() const {
|
|
+ if (m_started)
|
|
+ return m_process->name();
|
|
+ else
|
|
+ return QString();
|
|
+ }
|
|
+
|
|
+ void Method::start(const QString& user, const QString& session, const QString& password, bool passwordless) {
|
|
+ if (doStart(user, session, password, passwordless))
|
|
+ emit loginSucceeded(user);
|
|
+ else
|
|
+ emit loginFailed();
|
|
+ }
|
|
+
|
|
+ void Method::buildSessionName(const QString& session) {
|
|
+ if (session.endsWith(".desktop")) {
|
|
+ // session directory
|
|
+ QDir dir(Configuration::instance()->sessionsDir());
|
|
+
|
|
+ // session file
|
|
+ QFile file(dir.absoluteFilePath(session));
|
|
+
|
|
+ // open file
|
|
+ if (file.open(QIODevice::ReadOnly)) {
|
|
+
|
|
+ // read line-by-line
|
|
+ QTextStream in(&file);
|
|
+ while (!in.atEnd()) {
|
|
+ QString line = in.readLine();
|
|
+
|
|
+ // line starting with Exec
|
|
+ if (line.startsWith("Exec="))
|
|
+ m_sessionCommand = line.mid(5);
|
|
+ }
|
|
+
|
|
+ // close file
|
|
+ file.close();
|
|
+ }
|
|
+
|
|
+ // remove extension
|
|
+ m_sessionName = QString(session.left(session.lastIndexOf(".")));
|
|
+ } else {
|
|
+ m_sessionCommand = QString(session);
|
|
+ m_sessionName = QString(session);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ bool Method::authenticate() {
|
|
+#ifdef USE_PAM
|
|
+ if (m_pam)
|
|
+ m_pam->deleteLater();
|
|
+
|
|
+ m_pam = new PamService(m_user, m_password, m_passwordless);
|
|
+
|
|
+ if (!m_pam)
|
|
+ return false;
|
|
+/*
|
|
+ // set tty
|
|
+ if (!m_pam->setItem(PAM_TTY, ":0"))
|
|
+ return false;
|
|
+
|
|
+ // set display name
|
|
+ if (!m_pam->setItem(PAM_XDISPLAY, ":0"))
|
|
+ return false;
|
|
+*/
|
|
+ // set username
|
|
+ if (!m_pam->setItem(PAM_USER, qPrintable(m_user)))
|
|
+ return false;
|
|
+
|
|
+ // authenticate the applicant
|
|
+ if (!m_pam->authenticate())
|
|
+ return false;
|
|
+
|
|
+ // get mapped user name; PAM may have changed it
|
|
+ const char *mapped = (const char *) m_pam->getItem(PAM_USER);
|
|
+ if (mapped == NULL)
|
|
+ return false;
|
|
+ // TODO: Find out if PAM changing the name is a good or a bad thing
|
|
+ //m_user = QString(mapped);
|
|
+
|
|
+ if (!m_pam->acctMgmt())
|
|
+ return false;
|
|
+#else
|
|
+ if (!m_passwordless) {
|
|
+ // user name
|
|
+ struct passwd *pw;
|
|
+ if ((pw = getpwnam(qPrintable(m_user))) == nullptr) {
|
|
+ // log error
|
|
+ qCritical() << " AUTH: Failed to get user entry.";
|
|
+
|
|
+ // return fail
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ struct spwd *sp;
|
|
+ if ((sp = getspnam(pw->pw_name)) == nullptr) {
|
|
+ // log error
|
|
+ qCritical() << " AUTH: Failed to get shadow entry.";
|
|
+
|
|
+ // return fail
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ // check if password is not empty
|
|
+ if (sp->sp_pwdp && sp->sp_pwdp[0]) {
|
|
+
|
|
+ // encrypt password
|
|
+ char *encrypted = crypt(qPrintable(m_password), sp->sp_pwdp);
|
|
+
|
|
+ if (strcmp(encrypted, sp->sp_pwdp))
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ char *mapped = strdup(qPrintable(m_user));
|
|
+ m_user = QString(mapped);
|
|
+ free(mapped);
|
|
+#endif
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ bool Method::setupUser() {
|
|
+ // user name
|
|
+ struct passwd *pw;
|
|
+ if ((pw = getpwnam(qPrintable(m_user))) == nullptr) {
|
|
+ // log error
|
|
+ qCritical() << " AUTH: Failed to get user name.";
|
|
+
|
|
+ // return fail
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (pw->pw_shell[0] == '\0') {
|
|
+ setusershell();
|
|
+ strcpy(pw->pw_shell, getusershell());
|
|
+ endusershell();
|
|
+ }
|
|
+
|
|
+ // set session m_process params
|
|
+ m_process->setUser(pw->pw_name);
|
|
+ m_process->setDir(pw->pw_dir);
|
|
+ m_process->setUid(pw->pw_uid);
|
|
+ m_process->setGid(pw->pw_gid);
|
|
+ // redirect error output to ~/.xession-errors
|
|
+ m_process->setStandardErrorFile(QString("%1/.xsession-errors").arg(pw->pw_dir));
|
|
+ if (!AuthenticatorApp::instance()->requestCookieTo(QString("%1/.Xauthority").arg(pw->pw_dir), m_user))
|
|
+ return false;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ QProcessEnvironment Method::setupEnvironment() { // set m_process environment
|
|
+ QProcessEnvironment env = AuthenticatorApp::instance()->requestEnvironment(m_user);
|
|
+#ifdef USE_PAM
|
|
+ env.insert(m_pam->getEnv());
|
|
+ m_pam->putEnv(env);
|
|
+#endif
|
|
+ env.insert("DESKTOP_SESSION", m_sessionName);
|
|
+ env.insert("GDMSESSION", m_sessionName);
|
|
+ return env;
|
|
+ }
|
|
+
|
|
+ bool Method::startSession() {
|
|
+#ifdef USE_PAM
|
|
+ // set credentials
|
|
+ if (!m_pam->setCred(PAM_ESTABLISH_CRED))
|
|
+ return false;
|
|
+
|
|
+ // open session
|
|
+ if (!m_pam->openSession())
|
|
+ return false;
|
|
+
|
|
+ // set credentials
|
|
+ if (!m_pam->setCred(PAM_REINITIALIZE_CRED))
|
|
+ return false;
|
|
+#endif
|
|
+ // start session
|
|
+ m_process->start(Configuration::instance()->sessionCommand(), { m_sessionCommand });
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+
|
|
+ bool Method::doStart(const QString &user, const QString &session, const QString &password, bool passwordless) {
|
|
+ m_user = user;
|
|
+ m_password = password;
|
|
+ m_passwordless = passwordless;
|
|
+ qDebug() << " AUTH: Started for" << user << "with password" << password << "which will not be needed:" << passwordless << "to log into session" << session << ". Also, everybody will want to kill you if you don't put this message away for production.";
|
|
+ // check flag
|
|
+ if (m_started)
|
|
+ return false;
|
|
+
|
|
+ buildSessionName(session);
|
|
+
|
|
+ if (m_sessionCommand.isEmpty()) {
|
|
+ // log error
|
|
+ qCritical() << " AUTH: Failed to find command for session:" << session;
|
|
+
|
|
+ // return fail
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (!authenticate())
|
|
+ return false;
|
|
+
|
|
+ qDebug() << " AUTH: Authenticated for user" << m_user;
|
|
+
|
|
+ // create user session m_process
|
|
+ m_process = new Session(QString("Session%1").arg(AuthenticatorApp::instance()->requestSessionId()), this);
|
|
+ connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished()));
|
|
+
|
|
+ if (!setupUser())
|
|
+ return false;
|
|
+
|
|
+ m_process->setProcessEnvironment(setupEnvironment());
|
|
+
|
|
+ if (!startSession())
|
|
+ return false;
|
|
+
|
|
+ qDebug() << " AUTH: User session" << m_sessionName << "set up.";
|
|
+
|
|
+ // wait for started
|
|
+ if (!m_process->waitForStarted()) {
|
|
+ // log error
|
|
+ qDebug() << " AUTH: Failed to start user session.";
|
|
+
|
|
+ // return fail
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ // log message
|
|
+ qDebug() << " AUTH: User session started.";
|
|
+
|
|
+ // register to the display manager FIXME
|
|
+ // daemonApp->displayManager()->AddSession(m_process->name(), seat->name(), pw->pw_name);
|
|
+
|
|
+ // set flag
|
|
+ m_started = true;
|
|
+
|
|
+ // return success
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ void Method::stop() {
|
|
+ // check flag
|
|
+ if (!m_started)
|
|
+ return;
|
|
+
|
|
+ // log message
|
|
+ qDebug() << " AUTH: User session stopping...";
|
|
+
|
|
+ // terminate m_process
|
|
+ m_process->terminate();
|
|
+
|
|
+ // wait for finished
|
|
+ if (!m_process->waitForFinished(5000))
|
|
+ m_process->kill();
|
|
+ }
|
|
+
|
|
+ void Method::finished() {
|
|
+ // check flag
|
|
+ if (!m_started)
|
|
+ return;
|
|
+
|
|
+ // reset flag
|
|
+ m_started = false;
|
|
+
|
|
+ // log message
|
|
+ qDebug() << " AUTH: User session ended.";
|
|
+
|
|
+ // delete session process
|
|
+ m_process->deleteLater();
|
|
+ m_process = nullptr;
|
|
+
|
|
+#ifdef USE_PAM
|
|
+ delete m_pam;
|
|
+ m_pam = nullptr;
|
|
+#endif
|
|
+
|
|
+ emit sessionTerminated();
|
|
+ }
|
|
+
|
|
+};
|
|
+
|
|
+#include "Method.moc"
|
|
diff --git a/src/auth/Method.h b/src/auth/Method.h
|
|
new file mode 100644
|
|
index 0000000..e13133a
|
|
--- /dev/null
|
|
+++ b/src/auth/Method.h
|
|
@@ -0,0 +1,73 @@
|
|
+/*
|
|
+ * <one line to give the program's name and a brief idea of what it does.>
|
|
+ * Copyright (C) 2013 Martin Bříza <email>
|
|
+ *
|
|
+ * 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 METHOD_H
|
|
+#define METHOD_H
|
|
+
|
|
+#include <QtCore/QObject>
|
|
+#include <QtCore/QProcess>
|
|
+
|
|
+namespace SDDM {
|
|
+#ifdef USE_PAM
|
|
+ class PamService;
|
|
+#endif
|
|
+ class Session;
|
|
+ class Method : public QObject
|
|
+ {
|
|
+ Q_OBJECT
|
|
+ public:
|
|
+ explicit Method(QObject *parent = nullptr);
|
|
+ QString name() const;
|
|
+
|
|
+ protected:
|
|
+ virtual bool authenticate();
|
|
+ virtual bool setupUser();
|
|
+ virtual QProcessEnvironment setupEnvironment();
|
|
+ virtual bool startSession();
|
|
+
|
|
+ signals:
|
|
+ void loginSucceeded(QString);
|
|
+ void loginFailed();
|
|
+ void sessionTerminated();
|
|
+
|
|
+ public slots:
|
|
+ void start(const QString &user, const QString &session, const QString &password, bool passwordless);
|
|
+ void stop();
|
|
+ void finished();
|
|
+
|
|
+ private:
|
|
+ bool doStart(const QString &user, const QString &session, const QString &password, bool passwordless);
|
|
+ void buildSessionName(const QString& session);
|
|
+
|
|
+ bool m_passwordless { false };
|
|
+ QString m_user { };
|
|
+ QString m_password { };
|
|
+ QString m_sessionName { };
|
|
+ QString m_sessionCommand { };
|
|
+
|
|
+ Session *m_process { nullptr };
|
|
+ bool m_started { false };
|
|
+#ifdef USE_PAM
|
|
+ PamService *m_pam { nullptr };
|
|
+#endif
|
|
+ };
|
|
+}
|
|
+
|
|
+#endif // METHOD_H
|
|
diff --git a/src/auth/PAM.cpp b/src/auth/PAM.cpp
|
|
new file mode 100644
|
|
index 0000000..d9845d3
|
|
--- /dev/null
|
|
+++ b/src/auth/PAM.cpp
|
|
@@ -0,0 +1,262 @@
|
|
+/*
|
|
+ * PAM Authenticator backend
|
|
+ *
|
|
+ * Based on the work of:
|
|
+ * SDDM Authenticator implementation: Abdurrahman AVCI <abdurrahmanavci@gmail.com>
|
|
+ * SLiM PAM implementation: Martin Parm
|
|
+ *
|
|
+ * 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 "PAM.h"
|
|
+
|
|
+#include <QtCore/QDebug>
|
|
+
|
|
+namespace SDDM {
|
|
+
|
|
+ bool PamService::putEnv(const QProcessEnvironment& env) {
|
|
+ foreach (const QString& s, env.toStringList()) {
|
|
+ result = pam_putenv(handle, s.toAscii());
|
|
+ if (result != PAM_SUCCESS) {
|
|
+ qWarning() << " AUTH: PAM: putEnv:" << pam_strerror(handle, result);
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ QProcessEnvironment PamService::getEnv() {
|
|
+ QProcessEnvironment env;
|
|
+ // get pam environment
|
|
+ char **envlist = pam_getenvlist(handle);
|
|
+ if (envlist == NULL) {
|
|
+ qWarning() << " AUTH: PAM: getEnv: Returned NULL";
|
|
+ return env;
|
|
+ }
|
|
+
|
|
+ // copy it to the env map
|
|
+ for (int i = 0; envlist[i] != nullptr; ++i) {
|
|
+ QString s(envlist[i]);
|
|
+
|
|
+ // find equal sign
|
|
+ int index = s.indexOf('=');
|
|
+
|
|
+ // add to the hash
|
|
+ if (index != -1)
|
|
+ env.insert(s.left(index), s.mid(index + 1));
|
|
+
|
|
+ free(envlist[i]);
|
|
+ }
|
|
+ free(envlist);
|
|
+ return env;
|
|
+ }
|
|
+
|
|
+ bool PamService::chAuthTok(int flags) {
|
|
+ result = pam_chauthtok(handle, flags | m_silent);
|
|
+ if (result != PAM_SUCCESS) {
|
|
+ qWarning() << " AUTH: PAM: chAuthTok:" << pam_strerror(handle, result);
|
|
+ }
|
|
+ return result == PAM_SUCCESS;
|
|
+ }
|
|
+
|
|
+ bool PamService::acctMgmt(int flags) {
|
|
+ result = pam_acct_mgmt(handle, flags | m_silent);
|
|
+ if (result == PAM_NEW_AUTHTOK_REQD) {
|
|
+ // TODO see if this should really return the value or just true regardless of the outcome
|
|
+ return chAuthTok(PAM_CHANGE_EXPIRED_AUTHTOK);
|
|
+ }
|
|
+ else if (result != PAM_SUCCESS) {
|
|
+ qWarning() << " AUTH: PAM: acctMgmt:" << pam_strerror(handle, result);
|
|
+ return false;
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ bool PamService::authenticate(int flags) {
|
|
+ result = pam_authenticate(handle, flags | m_silent);
|
|
+ if (result != PAM_SUCCESS) {
|
|
+ qWarning() << " AUTH: PAM: authenticate:" << pam_strerror(handle, result);
|
|
+ }
|
|
+ return result == PAM_SUCCESS;
|
|
+ }
|
|
+
|
|
+ bool PamService::setCred(int flags) {
|
|
+ result = pam_setcred(handle, flags | m_silent);
|
|
+ if (result != PAM_SUCCESS) {
|
|
+ qWarning() << " AUTH: PAM: setCred:" << pam_strerror(handle, result);
|
|
+ }
|
|
+ return result == PAM_SUCCESS;
|
|
+ }
|
|
+
|
|
+ bool PamService::openSession() {
|
|
+ result = pam_open_session(handle, m_silent);
|
|
+ if (result != PAM_SUCCESS) {
|
|
+ qWarning() << " AUTH: PAM: openSession:" << pam_strerror(handle, result);
|
|
+ }
|
|
+ return result == PAM_SUCCESS;
|
|
+ }
|
|
+
|
|
+ bool PamService::closeSession() {
|
|
+ result = pam_close_session(handle, m_silent);
|
|
+ if (result != PAM_SUCCESS) {
|
|
+ qWarning() << " AUTH: PAM: closeSession:" << pam_strerror(handle, result);
|
|
+ }
|
|
+ return result == PAM_SUCCESS;
|
|
+ }
|
|
+
|
|
+ bool PamService::setItem(int item_type, const void* item) {
|
|
+ result = pam_set_item(handle, item_type, item);
|
|
+ if (result != PAM_SUCCESS) {
|
|
+ qWarning() << " AUTH: PAM: setItem:" << pam_strerror(handle, result);
|
|
+ }
|
|
+ return result == PAM_SUCCESS;
|
|
+ }
|
|
+
|
|
+ const void* PamService::getItem(int item_type) {
|
|
+ const void *item;
|
|
+ result = pam_get_item(handle, item_type, &item);
|
|
+ if (result != PAM_SUCCESS) {
|
|
+ qWarning() << " AUTH: PAM: getItem:" << pam_strerror(handle, result);
|
|
+ }
|
|
+ return item;
|
|
+ }
|
|
+
|
|
+ int PamService::converse(int n, const struct pam_message **msg, struct pam_response **resp, void *data) {
|
|
+ PamService *c = static_cast<PamService *>(data);
|
|
+ return c->doConverse(n, msg, resp);
|
|
+ }
|
|
+
|
|
+ int PamService::doConverse(int n, const struct pam_message **msg, struct pam_response **resp) {
|
|
+ struct pam_response *aresp;
|
|
+
|
|
+ // check size of the message buffer
|
|
+ if ((n <= 0) || (n > PAM_MAX_NUM_MSG))
|
|
+ return PAM_CONV_ERR;
|
|
+
|
|
+ // create response buffer
|
|
+ if ((aresp = (struct pam_response *) calloc(n, sizeof(struct pam_response))) == nullptr)
|
|
+ return PAM_BUF_ERR;
|
|
+
|
|
+ bool failed = false;
|
|
+
|
|
+ // if we don't require password, bail on any request from PAM
|
|
+ if (passwordless) {
|
|
+ for (int i = 0; i < n; ++i) {
|
|
+ switch(msg[i]->msg_style) {
|
|
+ case PAM_ERROR_MSG:
|
|
+ case PAM_TEXT_INFO:
|
|
+ qDebug() << " AUTH: PAM: Message" << msg[i]->msg;
|
|
+ break;
|
|
+ case PAM_PROMPT_ECHO_OFF:
|
|
+ case PAM_PROMPT_ECHO_ON:
|
|
+ default:
|
|
+ failed = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // else, respond to the messages
|
|
+ else {
|
|
+ for (int i = 0; i < n; ++i) {
|
|
+ aresp[i].resp_retcode = 0;
|
|
+ aresp[i].resp = nullptr;
|
|
+ switch (msg[i]->msg_style) {
|
|
+ case PAM_PROMPT_ECHO_OFF:
|
|
+ // set password - WARNING this is just assumption it's a password, beware!
|
|
+ aresp[i].resp = strdup(qPrintable(password));
|
|
+ if (aresp[i].resp == nullptr)
|
|
+ failed = true;
|
|
+ // clear password
|
|
+ password = "";
|
|
+ break;
|
|
+ case PAM_PROMPT_ECHO_ON:
|
|
+ // set user - WARNING again, just an assumption, in more complicated environments this won't suffice!
|
|
+ aresp[i].resp = strdup(qPrintable(user));
|
|
+ if (aresp[i].resp == nullptr)
|
|
+ failed = true;
|
|
+ // clear user
|
|
+ user = "";
|
|
+ break;
|
|
+ case PAM_ERROR_MSG:
|
|
+ case PAM_TEXT_INFO:
|
|
+ qDebug() << " AUTH: PAM: Message:" << msg[i]->msg;
|
|
+ break;
|
|
+ default:
|
|
+ failed = true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (failed) {
|
|
+ for (int i = 0; i < n; ++i) {
|
|
+ if (aresp[i].resp != nullptr) {
|
|
+ memset(aresp[i].resp, 0, strlen(aresp[i].resp));
|
|
+ free(aresp[i].resp);
|
|
+ }
|
|
+ }
|
|
+ memset(aresp, 0, n * sizeof(struct pam_response));
|
|
+ free(aresp);
|
|
+ *resp = nullptr;
|
|
+ return PAM_CONV_ERR;
|
|
+ }
|
|
+
|
|
+ *resp = aresp;
|
|
+ return PAM_SUCCESS;
|
|
+ }
|
|
+
|
|
+ bool PamService::start(const char *service_name, const char *user, const struct pam_conv *pam_conversation) {
|
|
+ result = pam_start(service_name, user, pam_conversation, &handle);
|
|
+ if (result != PAM_SUCCESS) {
|
|
+ qWarning() << " AUTH: PAM: start" << pam_strerror(handle, result);
|
|
+ return false;
|
|
+ }
|
|
+ else {
|
|
+ qDebug() << " AUTH: PAM: Starting...";
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ bool PamService::end(int flags) {
|
|
+ result = pam_end(handle, result | flags);
|
|
+ if (result != PAM_SUCCESS) {
|
|
+ qWarning() << " AUTH: PAM: end:" << pam_strerror(handle, result);
|
|
+ return false;
|
|
+ }
|
|
+ else {
|
|
+ qDebug() << " AUTH: PAM: Ended.";
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ PamService::PamService(const QString &user, const QString &password, bool passwordless, QObject *parent)
|
|
+ : QObject(parent), user(user), password(password), passwordless(passwordless) {
|
|
+ // create context
|
|
+ m_converse = { &PamService::converse, this };
|
|
+ // start service
|
|
+ if (passwordless)
|
|
+ start("sddm-passwordless", nullptr, &m_converse);
|
|
+ else
|
|
+ start("sddm", nullptr, &m_converse);
|
|
+ }
|
|
+
|
|
+ PamService::~PamService() {
|
|
+ // stop service
|
|
+ end();
|
|
+ }
|
|
+};
|
|
+
|
|
+#include "PAM.moc"
|
|
diff --git a/src/auth/PAM.h b/src/auth/PAM.h
|
|
new file mode 100644
|
|
index 0000000..f885ab5
|
|
--- /dev/null
|
|
+++ b/src/auth/PAM.h
|
|
@@ -0,0 +1,217 @@
|
|
+/*
|
|
+ * PAM Authenticator backend
|
|
+ * 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 PAM_H
|
|
+#define PAM_H
|
|
+#ifdef USE_PAM
|
|
+
|
|
+#include <QtCore/QObject>
|
|
+#include <QtCore/QProcess>
|
|
+
|
|
+#include <security/pam_appl.h>
|
|
+
|
|
+namespace SDDM {
|
|
+ /**
|
|
+ * Class wrapping the standard Linux-PAM library calls
|
|
+ *
|
|
+ * Almost everything is left the same except the following things:
|
|
+ *
|
|
+ * Mainly, state returns - if you call pam_start, pam_open_session and then
|
|
+ * pam_start again, the session will get closed and the conversation closed
|
|
+ *
|
|
+ * You don't need to pass PAM_SILENT to every call if you want PAM to be quiet.
|
|
+ * You can set the flag globally by using the \ref setSilence method.
|
|
+ *
|
|
+ * \ref acctMgmt doesn't require you to handle the PAM_NEW_AUTHTOK_REQD condition,
|
|
+ * it calls chAuthTok on its own.
|
|
+ *
|
|
+ * Error messages are automatically reported to qDebug
|
|
+ */
|
|
+ class PamService : public QObject {
|
|
+ Q_OBJECT
|
|
+
|
|
+ public:
|
|
+ /**
|
|
+ * ctor
|
|
+ *
|
|
+ * \param service PAM service name, e.g. "sddm"
|
|
+ * \param user username
|
|
+ * \param password user's password
|
|
+ * \param passwordless true if no password is required
|
|
+ * \param parent parent QObject
|
|
+ */
|
|
+ explicit PamService(const QString &user, const QString &password, bool passwordless, QObject *parent = 0);
|
|
+
|
|
+ virtual ~PamService();
|
|
+
|
|
+ /**
|
|
+ * Conversation function for the pam_conv structure
|
|
+ *
|
|
+ * Calls ((PamService*)pam_conv.appdata_ptr)->doConverse() with its parameters
|
|
+ */
|
|
+ static int converse(int n, const struct pam_message **msg, struct pam_response **resp, void *data);
|
|
+
|
|
+ /**
|
|
+ * The main conversation method
|
|
+ *
|
|
+ * This method relates to this particular session / login attempt only, it's called on the object
|
|
+ * that it belongs to.
|
|
+ *
|
|
+ * So far its architecture is quite silly and relies both on previously entered username and password.
|
|
+ * In the future, I'm intending to use it to request information from the greeter by calling its methods to
|
|
+ * supply the required information. (And this won't be just passwords, we'd like to have the possibility to
|
|
+ * log in using just a USB key, fingerprint reader, whatever you want.)
|
|
+ *
|
|
+ * I hope this task will be easier to implement by moving the whole thing into a class.
|
|
+ */
|
|
+ int doConverse(int n, const struct pam_message **msg, struct pam_response **resp);
|
|
+
|
|
+ /**
|
|
+ * pam_set_item - set and update PAM informations
|
|
+ *
|
|
+ * \param item_type PAM item type
|
|
+ * \param item item pointer
|
|
+ *
|
|
+ * \return true on success
|
|
+ */
|
|
+ bool setItem(int item_type, const void *item);
|
|
+
|
|
+ /**
|
|
+ * pam_get_item - getting PAM informations
|
|
+ *
|
|
+ * \param item_type
|
|
+ *
|
|
+ * \return item pointer or NULL on failure
|
|
+ */
|
|
+ const void *getItem(int item_type);
|
|
+
|
|
+ /**
|
|
+ * pam_open_session - start PAM session management
|
|
+ *
|
|
+ * \return true on success
|
|
+ */
|
|
+ bool openSession();
|
|
+
|
|
+ /**
|
|
+ * pam_close_session - terminate PAM session management
|
|
+ *
|
|
+ * \return true on success
|
|
+ */
|
|
+ bool closeSession();
|
|
+
|
|
+ /**
|
|
+ * pam_setcred - establish / delete user credentials
|
|
+ *
|
|
+ * \param flags PAM flag(s)
|
|
+ *
|
|
+ * \return true on success
|
|
+ */
|
|
+ bool setCred(int flags = 0);
|
|
+
|
|
+ /**
|
|
+ * pam_authenticate - account authentication
|
|
+ *
|
|
+ * \param flags PAM flag(s)
|
|
+ *
|
|
+ * \return true on success
|
|
+ */
|
|
+ bool authenticate(int flags = 0);
|
|
+
|
|
+ /**
|
|
+ * pam_acct_mgmt - PAM account validation management
|
|
+ *
|
|
+ * @note Automatically calls setCred if the password is expired
|
|
+ *
|
|
+ * \param flags PAM flag(s)
|
|
+ *
|
|
+ * \return true on success
|
|
+ */
|
|
+ bool acctMgmt(int flags = 0);
|
|
+
|
|
+ /**
|
|
+ * pam_chauthtok - updating authentication tokens
|
|
+ *
|
|
+ * \param flags PAM flag(s)
|
|
+ *
|
|
+ * \return true on success
|
|
+ */
|
|
+ bool chAuthTok(int flags = 0);
|
|
+
|
|
+ /**
|
|
+ * pam_getenv - get PAM environment
|
|
+ *
|
|
+ * \return Complete process environment
|
|
+ */
|
|
+ QProcessEnvironment getEnv();
|
|
+
|
|
+ /**
|
|
+ * pam_putenv - set or change PAM environment
|
|
+ *
|
|
+ * \param env environment to be merged into the PAM one
|
|
+ *
|
|
+ * \return true on success
|
|
+ */
|
|
+ bool putEnv(const QProcessEnvironment& env);
|
|
+
|
|
+ /**
|
|
+ * pam_end - termination of PAM transaction
|
|
+ *
|
|
+ * \param flags to be OR'd with the status (PAM_DATA_SILENT)
|
|
+ * \return true on success
|
|
+ */
|
|
+ bool end(int flags = 0);
|
|
+
|
|
+ /**
|
|
+ * pam_start - initialization of PAM transaction
|
|
+ *
|
|
+ * \param service PAM service name, e.g. "sddm"
|
|
+ * \param user username
|
|
+ * \param pam_conversation pointer to the PAM conversation structure to be used
|
|
+ *
|
|
+ * \return true on success
|
|
+ */
|
|
+ bool start(const char *service_name, const char *user, const struct pam_conv *pam_conversation);
|
|
+
|
|
+ /**
|
|
+ * Set PAM_SILENT upon the contained calls
|
|
+ * \param silent true if silent
|
|
+ */
|
|
+ inline void setSilence(bool silent){
|
|
+ if (silent)
|
|
+ m_silent |= PAM_SILENT;
|
|
+ else
|
|
+ m_silent &= (~PAM_SILENT);
|
|
+ }
|
|
+
|
|
+ private:
|
|
+ int m_silent { 0 }; ///< flag mask for silence of the contained calls
|
|
+
|
|
+ struct pam_conv m_converse; ///< the current conversation
|
|
+ pam_handle_t *handle { nullptr }; ///< PAM handle
|
|
+ int result { PAM_SUCCESS }; ///< PAM result
|
|
+
|
|
+ QString user { "" }; ///< user
|
|
+ QString password { "" }; ///< password
|
|
+ bool passwordless { false }; ///< true if doesn't require password
|
|
+ };
|
|
+};
|
|
+
|
|
+#endif // USE_PAM
|
|
+#endif // PAM_H
|
|
diff --git a/src/auth/Session.cpp b/src/auth/Session.cpp
|
|
new file mode 100644
|
|
index 0000000..138948a
|
|
--- /dev/null
|
|
+++ b/src/auth/Session.cpp
|
|
@@ -0,0 +1,107 @@
|
|
+/***************************************************************************
|
|
+* Copyright (c) 2013 Abdurrahman AVCI <abdurrahmanavci@gmail.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 "Session.h"
|
|
+
|
|
+#include "Configuration.h"
|
|
+
|
|
+#include <QDebug>
|
|
+
|
|
+#include <grp.h>
|
|
+#include <pwd.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+namespace SDDM {
|
|
+ Session::Session(const QString &name, QObject *parent) : QProcess(parent), m_name(name) {
|
|
+ }
|
|
+
|
|
+ const QString &Session::name() const {
|
|
+ return m_name;
|
|
+ }
|
|
+
|
|
+ void Session::setUser(const QString &user) {
|
|
+ m_user = user;
|
|
+ }
|
|
+
|
|
+ void Session::setDir(const QString &dir) {
|
|
+ m_dir = dir;
|
|
+ }
|
|
+
|
|
+ void Session::setUid(int uid) {
|
|
+ m_uid = uid;
|
|
+ }
|
|
+
|
|
+ void Session::setGid(int gid) {
|
|
+ m_gid = gid;
|
|
+ }
|
|
+
|
|
+ void Session::setupChildProcess() {
|
|
+ if (initgroups(qPrintable(m_user), m_gid)) {
|
|
+ qCritical() << " AUTH: Failed to initialize user groups.";
|
|
+
|
|
+ // emit signal
|
|
+ emit finished(EXIT_FAILURE, QProcess::NormalExit);
|
|
+
|
|
+ // exit
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+
|
|
+ if (setsid() < 0) {
|
|
+ qCritical() << " AUTH: Can't create a new session.";
|
|
+ emit finished(EXIT_FAILURE, QProcess::NormalExit);
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+
|
|
+ if (setgid(m_gid)) {
|
|
+ qCritical() << " AUTH: Failed to set group id.";
|
|
+
|
|
+ // emit signal
|
|
+ emit finished(EXIT_FAILURE, QProcess::NormalExit);
|
|
+
|
|
+ // exit
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+
|
|
+ if (setuid(m_uid)) {
|
|
+ qCritical() << " AUTH: Failed to set user id.";
|
|
+
|
|
+ // emit signal
|
|
+ emit finished(EXIT_FAILURE, QProcess::NormalExit);
|
|
+
|
|
+ // exit
|
|
+ exit(EXIT_FAILURE);
|
|
+
|
|
+ }
|
|
+/* FIXME
|
|
+ // add cookie
|
|
+ Display *display = qobject_cast<Display *>(authenticator->parent());
|
|
+ display->addCookie(QString("%1/.Xauthority").arg(m_dir));
|
|
+*/
|
|
+ // change to user home dir
|
|
+ if (chdir(qPrintable(m_dir))) {
|
|
+ qCritical() << " AUTH: Failed to change dir to user home.";
|
|
+
|
|
+ // emit signal
|
|
+ emit finished(EXIT_FAILURE, QProcess::NormalExit);
|
|
+
|
|
+ // exit
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/auth/Session.h b/src/auth/Session.h
|
|
new file mode 100644
|
|
index 0000000..1f075d3
|
|
--- /dev/null
|
|
+++ b/src/auth/Session.h
|
|
@@ -0,0 +1,51 @@
|
|
+/***************************************************************************
|
|
+* Copyright (c) 2013 Abdurrahman AVCI <abdurrahmanavci@gmail.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_SESSION_H
|
|
+#define SDDM_SESSION_H
|
|
+
|
|
+#include <QProcess>
|
|
+
|
|
+namespace SDDM {
|
|
+ class Session : public QProcess {
|
|
+ Q_OBJECT
|
|
+ Q_DISABLE_COPY(Session)
|
|
+ public:
|
|
+ explicit Session(const QString &name, QObject *parent = 0);
|
|
+
|
|
+ const QString &name() const;
|
|
+
|
|
+ void setUser(const QString &user);
|
|
+ void setDir(const QString &dir);
|
|
+ void setUid(int uid);
|
|
+ void setGid(int gid);
|
|
+
|
|
+ protected:
|
|
+ void setupChildProcess();
|
|
+
|
|
+ private:
|
|
+ QString m_name { "" };
|
|
+ QString m_user { "" };
|
|
+ QString m_dir { "" };
|
|
+ int m_uid { 0 };
|
|
+ int m_gid { 0 };
|
|
+ };
|
|
+}
|
|
+
|
|
+#endif // SDDM_SESSION_H
|
|
diff --git a/src/common/.AuthenticatorWrapper.cpp.kate-swp b/src/common/.AuthenticatorWrapper.cpp.kate-swp
|
|
new file mode 100644
|
|
index 0000000..3253e12
|
|
Binary files /dev/null and b/src/common/.AuthenticatorWrapper.cpp.kate-swp differ
|
|
diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp
|
|
index 4b780b3..2095b05 100644
|
|
--- a/src/common/Configuration.cpp
|
|
+++ b/src/common/Configuration.cpp
|
|
@@ -63,7 +63,6 @@ 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()) {
|
|
@@ -123,7 +122,6 @@ namespace SDDM {
|
|
} else {
|
|
d->numlock = Configuration::NUM_NONE;
|
|
}
|
|
- d->xdmcpServerEnabled = settings.value("XDMCPServer", d->xdmcpServerEnabled).toBool();
|
|
}
|
|
|
|
void Configuration::save() {
|
|
@@ -160,8 +158,6 @@ 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() {
|
|
@@ -265,9 +261,4 @@ 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 4b610d8..cbef261 100644
|
|
--- a/src/common/Configuration.h
|
|
+++ b/src/common/Configuration.h
|
|
@@ -79,8 +79,6 @@ 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/common/Messages.h b/src/common/Messages.h
|
|
index c779791..00f27de 100644
|
|
--- a/src/common/Messages.h
|
|
+++ b/src/common/Messages.h
|
|
@@ -40,6 +40,20 @@ namespace SDDM {
|
|
LoginFailed
|
|
};
|
|
|
|
+ enum class AuthMessages {
|
|
+ AuthNone = 0,
|
|
+ Start,
|
|
+ End,
|
|
+ RequestEnv,
|
|
+ Env,
|
|
+ LoginFailed,
|
|
+ LoginSucceeded,
|
|
+ RequestSessionID,
|
|
+ SessionID,
|
|
+ RequestCookieLink,
|
|
+ CookieLink
|
|
+ };
|
|
+
|
|
enum Capability {
|
|
None = 0x0000,
|
|
PowerOff = 0x0001,
|
|
diff --git a/src/daemon/Authenticator.cpp b/src/daemon/Authenticator.cpp
|
|
index bd7a88c..4db3f42 100644
|
|
--- a/src/daemon/Authenticator.cpp
|
|
+++ b/src/daemon/Authenticator.cpp
|
|
@@ -18,408 +18,123 @@
|
|
***************************************************************************/
|
|
|
|
#include "Authenticator.h"
|
|
-
|
|
-#include "Configuration.h"
|
|
#include "DaemonApp.h"
|
|
#include "Display.h"
|
|
#include "DisplayManager.h"
|
|
+#include "SeatManager.h"
|
|
#include "Seat.h"
|
|
-#include "Session.h"
|
|
-
|
|
-#include <QDebug>
|
|
-#include <QDir>
|
|
-#include <QFile>
|
|
-#include <QTextStream>
|
|
+#include "Constants.h"
|
|
|
|
-#ifdef USE_PAM
|
|
-#include <security/pam_appl.h>
|
|
-#else
|
|
-#include <crypt.h>
|
|
-#include <shadow.h>
|
|
-#endif
|
|
+#include <QtCore/QDebug>
|
|
+#include <QtCore/QFile>
|
|
|
|
-#include <grp.h>
|
|
#include <pwd.h>
|
|
#include <unistd.h>
|
|
|
|
namespace SDDM {
|
|
-#ifdef USE_PAM
|
|
- class PamService {
|
|
- public:
|
|
- PamService(const char *service, const QString &user, const QString &password, bool passwordless);
|
|
- ~PamService();
|
|
-
|
|
- struct pam_conv m_converse;
|
|
- pam_handle_t *handle { nullptr };
|
|
- int result { PAM_SUCCESS };
|
|
-
|
|
- QString user { "" };
|
|
- QString password { "" };
|
|
- bool passwordless { false };
|
|
- };
|
|
-
|
|
- int converse(int n, const struct pam_message **msg, struct pam_response **resp, void *data) {
|
|
- struct pam_response *aresp;
|
|
-
|
|
- // check size of the message buffer
|
|
- if ((n <= 0) || (n > PAM_MAX_NUM_MSG))
|
|
- return PAM_CONV_ERR;
|
|
-
|
|
- // create response buffer
|
|
- if ((aresp = (struct pam_response *) calloc(n, sizeof(struct pam_response))) == nullptr)
|
|
- return PAM_BUF_ERR;
|
|
-
|
|
- // respond to the messages
|
|
- bool failed = false;
|
|
- for (int i = 0; i < n; ++i) {
|
|
- aresp[i].resp_retcode = 0;
|
|
- aresp[i].resp = nullptr;
|
|
- switch (msg[i]->msg_style) {
|
|
- case PAM_PROMPT_ECHO_OFF: {
|
|
- PamService *c = static_cast<PamService *>(data);
|
|
- // set password
|
|
- aresp[i].resp = strdup(qPrintable(c->password));
|
|
- if (aresp[i].resp == nullptr)
|
|
- failed = true;
|
|
- // clear password
|
|
- c->password = "";
|
|
- }
|
|
- break;
|
|
- case PAM_PROMPT_ECHO_ON: {
|
|
- PamService *c = static_cast<PamService *>(data);
|
|
- // set user
|
|
- aresp[i].resp = strdup(qPrintable(c->user));
|
|
- if (aresp[i].resp == nullptr)
|
|
- failed = true;
|
|
- // clear user
|
|
- c->user = "";
|
|
- }
|
|
- break;
|
|
- case PAM_ERROR_MSG:
|
|
- case PAM_TEXT_INFO:
|
|
- break;
|
|
- default:
|
|
- failed = true;
|
|
- }
|
|
- }
|
|
-
|
|
- if (failed) {
|
|
- for (int i = 0; i < n; ++i) {
|
|
- if (aresp[i].resp != nullptr) {
|
|
- memset(aresp[i].resp, 0, strlen(aresp[i].resp));
|
|
- free(aresp[i].resp);
|
|
- }
|
|
- }
|
|
- memset(aresp, 0, n * sizeof(struct pam_response));
|
|
- free(aresp);
|
|
- *resp = nullptr;
|
|
- return PAM_CONV_ERR;
|
|
+ Authenticator::Authenticator(Display *parent)
|
|
+ : QProcess(parent)
|
|
+ , m_display(parent) {
|
|
+ connect(this, SIGNAL(finished(int)), this, SIGNAL(stopped()));
|
|
+ setReadChannel(QProcess::StandardOutput);
|
|
+ connect(this, SIGNAL(readyRead()), this, SLOT(readFromChild()));
|
|
+ connect(this, SIGNAL(readyReadStandardError()), SLOT(forwardErrorOutput()));
|
|
+
|
|
+ QProcess::start(QString("%1/sddm-auth").arg(BIN_INSTALL_DIR));
|
|
+ if (!waitForStarted()) {
|
|
+ qCritical() << " DAEMON: Failed to start authenticator process:" << errorString();
|
|
+ return;
|
|
}
|
|
|
|
- *resp = aresp;
|
|
- return PAM_SUCCESS;
|
|
- }
|
|
-
|
|
- PamService::PamService(const char *service, const QString &user, const QString &password, bool passwordless) : user(user), password(password), passwordless(passwordless) {
|
|
- // create context
|
|
- m_converse = { &converse, this };
|
|
-
|
|
- // start service
|
|
- pam_start(service, nullptr, &m_converse, &handle);
|
|
- }
|
|
-
|
|
- PamService::~PamService() {
|
|
- // stop service
|
|
- pam_end(handle, result);
|
|
- }
|
|
-#endif
|
|
-
|
|
- Authenticator::Authenticator(QObject *parent) : QObject(parent) {
|
|
- }
|
|
-
|
|
- Authenticator::~Authenticator() {
|
|
- stop();
|
|
+ m_started = true;
|
|
+ qDebug() << " DAEMON: Started the authenticator process.";
|
|
}
|
|
|
|
- bool Authenticator::start(const QString &user, const QString &session) {
|
|
- return doStart(user, QString(), session, true);
|
|
+ void Authenticator::forwardErrorOutput() {
|
|
+ QFile err;
|
|
+ err.open(fileno(stderr), QIODevice::WriteOnly | QIODevice::Unbuffered);
|
|
+ err.write(this->readAllStandardError());
|
|
}
|
|
|
|
- bool Authenticator::start(const QString &user, const QString &password, const QString &session) {
|
|
- return doStart(user, password, session, false);
|
|
+ void Authenticator::readFromChild() {
|
|
+ QDataStream stream(this);
|
|
+ while (this->bytesAvailable()) {
|
|
+ quint32 command;
|
|
+ stream >> command;
|
|
+ qDebug() << " DAEMON: Received message" << command << "from the authenticator";
|
|
+ handleMessage(AuthMessages(command));
|
|
+ if (stream.status() != QDataStream::Ok)
|
|
+ break;
|
|
+ }
|
|
}
|
|
|
|
- bool Authenticator::doStart(const QString &user, const QString &password, const QString &session, bool passwordless) {
|
|
- // check flag
|
|
- if (m_started)
|
|
- return false;
|
|
-
|
|
- // convert session to command
|
|
- QString sessionName = "";
|
|
- QString command = "";
|
|
-
|
|
- if (session.endsWith(".desktop")) {
|
|
- // session directory
|
|
- QDir dir(daemonApp->configuration()->sessionsDir());
|
|
-
|
|
- // session file
|
|
- QFile file(dir.absoluteFilePath(session));
|
|
-
|
|
- // open file
|
|
- if (file.open(QIODevice::ReadOnly)) {
|
|
-
|
|
- // read line-by-line
|
|
- QTextStream in(&file);
|
|
- while (!in.atEnd()) {
|
|
- QString line = in.readLine();
|
|
-
|
|
- // line starting with Exec
|
|
- if (line.startsWith("Exec="))
|
|
- command = line.mid(5);
|
|
+ void Authenticator::handleMessage(AuthMessages command) {
|
|
+ QDataStream stream(this);
|
|
+ switch (command) {
|
|
+ case AuthMessages::RequestEnv: {
|
|
+ QString user;
|
|
+ stream >> user;
|
|
+ QStringList env = m_display->sessionEnv(user).toStringList();
|
|
+ stream << quint32(AuthMessages::Env) << env.count();
|
|
+ foreach (const QString &s, env) {
|
|
+ stream << s;
|
|
}
|
|
-
|
|
- // close file
|
|
- file.close();
|
|
+ break;
|
|
}
|
|
-
|
|
- // remove extension
|
|
- sessionName = session.left(session.lastIndexOf("."));
|
|
- } else {
|
|
- command = session;
|
|
- sessionName = session;
|
|
- }
|
|
-
|
|
- if (command.isEmpty()) {
|
|
- // log error
|
|
- qCritical() << " DAEMON: Failed to find command for session:" << session;
|
|
-
|
|
- // return fail
|
|
- return false;
|
|
- }
|
|
-
|
|
- // get display and display
|
|
- Display *display = qobject_cast<Display *>(parent());
|
|
- Seat *seat = qobject_cast<Seat *>(display->parent());
|
|
-
|
|
-#ifdef USE_PAM
|
|
- if (m_pam)
|
|
- delete m_pam;
|
|
-
|
|
- m_pam = new PamService("sddm", user, password, passwordless);
|
|
-
|
|
- if (!m_pam)
|
|
- return false;
|
|
-
|
|
- if (!passwordless) {
|
|
- // authenticate the applicant
|
|
- if ((m_pam->result = pam_authenticate(m_pam->handle, 0)) != PAM_SUCCESS)
|
|
- return false;
|
|
-
|
|
- if ((m_pam->result = pam_acct_mgmt(m_pam->handle, 0)) == PAM_NEW_AUTHTOK_REQD)
|
|
- m_pam->result = pam_chauthtok(m_pam->handle, PAM_CHANGE_EXPIRED_AUTHTOK);
|
|
-
|
|
- if (m_pam->result != PAM_SUCCESS)
|
|
- return false;
|
|
- }
|
|
-
|
|
- // set username
|
|
- if ((m_pam->result = pam_set_item(m_pam->handle, PAM_USER, qPrintable(user))) != PAM_SUCCESS)
|
|
- return false;
|
|
-
|
|
- // set credentials
|
|
- if ((m_pam->result = pam_setcred(m_pam->handle, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
|
|
- return false;
|
|
-
|
|
- // set tty
|
|
- if ((m_pam->result = pam_set_item(m_pam->handle, PAM_TTY, qPrintable(display->name()))) != PAM_SUCCESS)
|
|
- return false;
|
|
-
|
|
- // set display name
|
|
- if ((m_pam->result = pam_set_item(m_pam->handle, PAM_XDISPLAY, qPrintable(display->name()))) != PAM_SUCCESS)
|
|
- return false;
|
|
-
|
|
- // open session
|
|
- if ((m_pam->result = pam_open_session(m_pam->handle, 0)) != PAM_SUCCESS)
|
|
- return false;
|
|
-
|
|
- // get mapped user name; PAM may have changed it
|
|
- char *mapped;
|
|
- if ((m_pam->result = pam_get_item(m_pam->handle, PAM_USER, (const void **)&mapped)) != PAM_SUCCESS)
|
|
- return false;
|
|
-#else
|
|
- if (!passwordless) {
|
|
- // user name
|
|
- struct passwd *pw;
|
|
- if ((pw = getpwnam(qPrintable(user))) == nullptr) {
|
|
- // log error
|
|
- qCritical() << " DAEMON: Failed to get user entry.";
|
|
-
|
|
- // return fail
|
|
- return false;
|
|
+ case AuthMessages::LoginFailed:
|
|
+ emit loginFailed(m_parentSocket);
|
|
+ break;
|
|
+ case AuthMessages::LoginSucceeded: {
|
|
+ QString user;
|
|
+ stream >> m_name >> user;
|
|
+ daemonApp->displayManager()->AddSession(m_name, qobject_cast<Seat*>(m_display->parent())->name(), user);
|
|
+ emit loginSucceeded(m_parentSocket);
|
|
+ break;
|
|
}
|
|
-
|
|
- struct spwd *sp;
|
|
- if ((sp = getspnam(pw->pw_name)) == nullptr) {
|
|
- // log error
|
|
- qCritical() << " DAEMON: Failed to get shadow entry.";
|
|
-
|
|
- // return fail
|
|
- return false;
|
|
+ case AuthMessages::RequestSessionID:
|
|
+ stream << quint32(AuthMessages::SessionID) << int(DaemonApp::instance()->newSessionId());
|
|
+ break;
|
|
+ case AuthMessages::RequestCookieLink: {
|
|
+ QString path, user;
|
|
+ struct passwd *pw;
|
|
+ stream >> path >> user;
|
|
+ qDebug() << "The path is" << path << "and the user" << user;
|
|
+ m_display->addCookie(path);
|
|
+ pw = getpwnam(qPrintable(user));
|
|
+ if(pw)
|
|
+ chown(qPrintable(path), pw->pw_uid, pw->pw_gid);
|
|
+ stream << quint32(AuthMessages::CookieLink);
|
|
+ break;
|
|
}
|
|
-
|
|
- // check if password is not empty
|
|
- if (sp->sp_pwdp && sp->sp_pwdp[0]) {
|
|
-
|
|
- // encrypt password
|
|
- char *encrypted = crypt(qPrintable(password), sp->sp_pwdp);
|
|
-
|
|
- if (strcmp(encrypted, sp->sp_pwdp))
|
|
- return false;
|
|
- }
|
|
- }
|
|
-
|
|
- char *mapped = strdup(qPrintable(user));
|
|
-#endif
|
|
-
|
|
- // user name
|
|
- struct passwd *pw;
|
|
- if ((pw = getpwnam(mapped)) == nullptr) {
|
|
- // log error
|
|
- qCritical() << " DAEMON: Failed to get user name.";
|
|
-
|
|
- // return fail
|
|
- return false;
|
|
- }
|
|
-
|
|
- if (pw->pw_shell[0] == '\0') {
|
|
- setusershell();
|
|
- strcpy(pw->pw_shell, getusershell());
|
|
- endusershell();
|
|
- }
|
|
-
|
|
- // create user session process
|
|
- process = new Session(QString("Session%1").arg(daemonApp->newSessionId()), this);
|
|
-
|
|
- // set session process params
|
|
- process->setUser(pw->pw_name);
|
|
- process->setDir(pw->pw_dir);
|
|
- process->setUid(pw->pw_uid);
|
|
- process->setGid(pw->pw_gid);
|
|
-
|
|
- // set process environment
|
|
- QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
|
-#ifdef USE_PAM
|
|
- // get pam environment
|
|
- char **envlist = pam_getenvlist(m_pam->handle);
|
|
-
|
|
- // copy it to the env map
|
|
- for (int i = 0; envlist[i] != nullptr; ++i) {
|
|
- QString s(envlist[i]);
|
|
-
|
|
- // find equal sign
|
|
- int index = s.indexOf('=');
|
|
-
|
|
- // add to the hash
|
|
- if (index != -1)
|
|
- env.insert(s.left(index), s.mid(index + 1));
|
|
- }
|
|
-#else
|
|
- // we strdup'd the string before in this branch
|
|
- free(mapped);
|
|
-#endif
|
|
- env.insert("HOME", pw->pw_dir);
|
|
- env.insert("PWD", pw->pw_dir);
|
|
- env.insert("SHELL", pw->pw_shell);
|
|
- env.insert("USER", pw->pw_name);
|
|
- env.insert("LOGNAME", pw->pw_name);
|
|
- env.insert("PATH", daemonApp->configuration()->defaultPath());
|
|
- env.insert("DISPLAY", display->name());
|
|
- env.insert("XAUTHORITY", QString("%1/.Xauthority").arg(pw->pw_dir));
|
|
- env.insert("XDG_SEAT", seat->name());
|
|
- env.insert("XDG_SEAT_PATH", daemonApp->displayManager()->seatPath(seat->name()));
|
|
- env.insert("XDG_SESSION_PATH", daemonApp->displayManager()->sessionPath(process->name()));
|
|
- env.insert("XDG_VTNR", QString::number(display->terminalId()));
|
|
- env.insert("DESKTOP_SESSION", sessionName);
|
|
- env.insert("GDMSESSION", sessionName);
|
|
- process->setProcessEnvironment(env);
|
|
-
|
|
- // redirect error output to ~/.xession-errors
|
|
- process->setStandardErrorFile(QString("%1/.xsession-errors").arg(pw->pw_dir));
|
|
-
|
|
- // start session
|
|
- process->start(daemonApp->configuration()->sessionCommand(), { command });
|
|
-
|
|
- // connect signal
|
|
- connect(process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished()));
|
|
-
|
|
- // wait for started
|
|
- if (!process->waitForStarted()) {
|
|
- // log error
|
|
- qDebug() << " DAEMON: Failed to start user session.";
|
|
-
|
|
- // return fail
|
|
- return false;
|
|
+ default:
|
|
+ qWarning() << " DAEMON: Child sent message type" << quint32(command) << "which cannot be handled.";
|
|
+ break;
|
|
}
|
|
-
|
|
- // log message
|
|
- qDebug() << " DAEMON: User session started.";
|
|
-
|
|
- // register to the display manager
|
|
- daemonApp->displayManager()->AddSession(process->name(), seat->name(), pw->pw_name);
|
|
-
|
|
- // set flag
|
|
- m_started = true;
|
|
-
|
|
- // return success
|
|
- return true;
|
|
}
|
|
|
|
- void Authenticator::stop() {
|
|
- // check flag
|
|
+ void Authenticator::start(QLocalSocket *socket, const QString& user, const QString& session, const QString& password, bool passwordless) {
|
|
if (!m_started)
|
|
return;
|
|
|
|
- // log message
|
|
- qDebug() << " DAEMON: User session stopping...";
|
|
+ m_parentSocket = socket;
|
|
|
|
- // terminate process
|
|
- process->terminate();
|
|
+ QDataStream stream(this);
|
|
+ stream << quint32(AuthMessages::Start) << user << session << password << passwordless;
|
|
|
|
- // wait for finished
|
|
- if (!process->waitForFinished(5000))
|
|
- process->kill();
|
|
+ qDebug() << " DAEMON: Starting authentication for user" << user;
|
|
}
|
|
|
|
- void Authenticator::finished() {
|
|
- // check flag
|
|
+ void Authenticator::stop() {
|
|
if (!m_started)
|
|
return;
|
|
|
|
- // reset flag
|
|
- m_started = false;
|
|
-
|
|
- // log message
|
|
- qDebug() << " DAEMON: User session ended.";
|
|
-
|
|
// unregister from the display manager
|
|
- daemonApp->displayManager()->RemoveSession(process->name());
|
|
+ daemonApp->displayManager()->RemoveSession(m_name);
|
|
|
|
- // delete session process
|
|
- process->deleteLater();
|
|
- process = nullptr;
|
|
+ QDataStream stream(this);
|
|
+ stream << quint32(AuthMessages::End);
|
|
|
|
-#ifdef USE_PAM
|
|
- 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;
|
|
- }
|
|
-#endif
|
|
-
|
|
- // emit signal
|
|
- emit stopped();
|
|
+ m_started = false;
|
|
+ qDebug() << " DAEMON: Stopped the authenticator process";
|
|
}
|
|
}
|
|
diff --git a/src/daemon/Authenticator.h b/src/daemon/Authenticator.h
|
|
index 23e91ec..4989af4 100644
|
|
--- a/src/daemon/Authenticator.h
|
|
+++ b/src/daemon/Authenticator.h
|
|
@@ -20,42 +20,40 @@
|
|
#ifndef SDDM_AUTHENTICATOR_H
|
|
#define SDDM_AUTHENTICATOR_H
|
|
|
|
+#include "Messages.h"
|
|
+
|
|
#include <QObject>
|
|
+#include <QtCore/QProcess>
|
|
|
|
+class QLocalSocket;
|
|
namespace SDDM {
|
|
-#ifdef USE_PAM
|
|
- class PamService;
|
|
-#endif
|
|
- class Session;
|
|
|
|
- class AuthenticatorPrivate;
|
|
- class Authenticator : public QObject {
|
|
+ class Display;
|
|
+ class Authenticator : public QProcess {
|
|
Q_OBJECT
|
|
Q_DISABLE_COPY(Authenticator)
|
|
public:
|
|
- Authenticator(QObject *parent = 0);
|
|
- ~Authenticator();
|
|
+ explicit Authenticator(Display *parent = nullptr);
|
|
|
|
- public slots:
|
|
- bool start(const QString &user, const QString &session);
|
|
- bool start(const QString &user, const QString &password, const QString &session);
|
|
+ private slots:
|
|
+ void readFromChild();
|
|
+ void handleMessage(AuthMessages command);
|
|
+ void forwardErrorOutput();
|
|
|
|
+ public slots:
|
|
+ void start(QLocalSocket *socket, const QString& user, const QString& session, const QString& password, bool passwordless);
|
|
void stop();
|
|
- void finished();
|
|
|
|
signals:
|
|
+ void loginFailed(QLocalSocket*);
|
|
+ void loginSucceeded(QLocalSocket*);
|
|
void stopped();
|
|
|
|
private:
|
|
- bool doStart(const QString &user, const QString &password, const QString &session, bool passwordless);
|
|
-
|
|
+ QString m_name;
|
|
+ Display *m_display { nullptr };
|
|
+ QLocalSocket *m_parentSocket { nullptr }; // to be got rid of soon
|
|
bool m_started { false };
|
|
-
|
|
-#ifdef USE_PAM
|
|
- PamService *m_pam { nullptr };
|
|
-#endif
|
|
-
|
|
- Session *process { nullptr };
|
|
};
|
|
}
|
|
|
|
diff --git a/src/daemon/DaemonApp.cpp b/src/daemon/DaemonApp.cpp
|
|
index 616282e..c40cdea 100644
|
|
--- a/src/daemon/DaemonApp.cpp
|
|
+++ b/src/daemon/DaemonApp.cpp
|
|
@@ -25,7 +25,6 @@
|
|
#include "PowerManager.h"
|
|
#include "SeatManager.h"
|
|
#include "SignalHandler.h"
|
|
-#include "xdmcp/Server.h"
|
|
|
|
#ifdef USE_QT5
|
|
#include "MessageHandler.h"
|
|
@@ -66,12 +65,6 @@ 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 2088010..81f955c 100644
|
|
--- a/src/daemon/DaemonApp.h
|
|
+++ b/src/daemon/DaemonApp.h
|
|
@@ -29,9 +29,6 @@ namespace SDDM {
|
|
class DisplayManager;
|
|
class PowerManager;
|
|
class SeatManager;
|
|
- namespace XDMCP {
|
|
- class Server;
|
|
- }
|
|
|
|
class DaemonApp : public QCoreApplication {
|
|
Q_OBJECT
|
|
@@ -60,7 +57,6 @@ 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 80aa95a..d473fdb 100644
|
|
--- a/src/daemon/Display.cpp
|
|
+++ b/src/daemon/Display.cpp
|
|
@@ -23,9 +23,11 @@
|
|
#include "Configuration.h"
|
|
#include "DaemonApp.h"
|
|
#include "DisplayServer.h"
|
|
+#include "DisplayManager.h"
|
|
#include "Seat.h"
|
|
#include "SocketServer.h"
|
|
#include "Greeter.h"
|
|
+#include <pwd.h>
|
|
|
|
#include <QDebug>
|
|
#include <QDir>
|
|
@@ -53,19 +55,6 @@ 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)),
|
|
@@ -75,17 +64,12 @@ namespace SDDM {
|
|
|
|
m_display = QString(":%1").arg(m_displayId);
|
|
|
|
- // 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()));
|
|
|
|
+ // restart display after display server ended
|
|
+ connect(m_displayServer, SIGNAL(stopped()), this, SLOT(stop()));
|
|
+
|
|
// connect login signal
|
|
connect(m_socketServer, SIGNAL(login(QLocalSocket*,QString,QString,QString)), this, SLOT(login(QLocalSocket*,QString,QString,QString)));
|
|
|
|
@@ -108,22 +92,6 @@ 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() {
|
|
@@ -146,22 +114,38 @@ 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);
|
|
+ QProcessEnvironment Display::sessionEnv(const QString& user) const {
|
|
+ struct passwd *pw;
|
|
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
|
+ Seat *seat = qobject_cast<Seat *>(parent());
|
|
+
|
|
+ if ((pw = getpwnam(qPrintable(user))) == nullptr) {
|
|
+ // log error
|
|
+ qCritical() << " DAEMON: Failed to get user name.";
|
|
+
|
|
+ // return fail
|
|
+ return QProcessEnvironment();
|
|
}
|
|
- return cookie;
|
|
+ env.insert("HOME", pw->pw_dir);
|
|
+ env.insert("PWD", pw->pw_dir);
|
|
+ env.insert("SHELL", pw->pw_shell);
|
|
+ env.insert("USER", pw->pw_name);
|
|
+ env.insert("LOGNAME", pw->pw_name);
|
|
+ env.insert("PATH", daemonApp->configuration()->defaultPath());
|
|
+ env.insert("DISPLAY", name());
|
|
+ env.insert("XAUTHORITY", QString("%1/.Xauthority").arg(pw->pw_dir));
|
|
+ env.insert("XDG_SEAT", seat->name());
|
|
+ env.insert("XDG_SEAT_PATH", daemonApp->displayManager()->seatPath(seat->name()));
|
|
+ env.insert("XDG_VTNR", QString::number(terminalId()));
|
|
+ return env;
|
|
}
|
|
|
|
void Display::addCookie(const QString &file) {
|
|
// log message
|
|
qDebug() << " DAEMON: Adding cookie to" << file;
|
|
|
|
- // remove file
|
|
- QFile::remove(file);
|
|
+ // remove the file
|
|
+ QFile::remove(m_authPath);
|
|
|
|
QString cmd = QString("%1 -f %2 -q").arg(daemonApp->configuration()->xauthPath()).arg(file);
|
|
|
|
@@ -183,14 +167,28 @@ namespace SDDM {
|
|
if (m_started)
|
|
return;
|
|
|
|
- if (m_displayServer != nullptr) {
|
|
- // set display server params
|
|
- m_displayServer->setDisplay(m_display);
|
|
- m_displayServer->setAuthPath(m_authPath);
|
|
+ // generate cookie
|
|
+ std::random_device rd;
|
|
+ std::mt19937 gen(rd());
|
|
+ std::uniform_int_distribution<> dis(0, 15);
|
|
|
|
- // start display server
|
|
- m_displayServer->start();
|
|
- }
|
|
+ // 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();
|
|
|
|
if ((daemonApp->configuration()->first || daemonApp->configuration()->autoRelogin()) &&
|
|
!daemonApp->configuration()->autoUser().isEmpty() && !daemonApp->configuration()->lastSession().isEmpty()) {
|
|
@@ -201,7 +199,7 @@ namespace SDDM {
|
|
m_started = true;
|
|
|
|
// start session
|
|
- m_authenticator->start(daemonApp->configuration()->autoUser(), daemonApp->configuration()->lastSession());
|
|
+ m_authenticator->start(nullptr, daemonApp->configuration()->autoUser(), daemonApp->configuration()->lastSession(), QString(), true);
|
|
|
|
// return
|
|
return;
|
|
@@ -246,11 +244,9 @@ namespace SDDM {
|
|
m_socketServer->stop();
|
|
|
|
// stop display server
|
|
- if (m_displayServer != nullptr) {
|
|
- m_displayServer->blockSignals(true);
|
|
- m_displayServer->stop();
|
|
- m_displayServer->blockSignals(false);
|
|
- }
|
|
+ m_displayServer->blockSignals(true);
|
|
+ m_displayServer->stop();
|
|
+ m_displayServer->blockSignals(false);
|
|
|
|
// remove authority file
|
|
QFile::remove(m_authPath);
|
|
@@ -264,20 +260,13 @@ namespace SDDM {
|
|
|
|
void Display::login(QLocalSocket *socket, const QString &user, const QString &password, const QString &session) {
|
|
// start session
|
|
- if (!m_authenticator->start(user, password, session)) {
|
|
- // emit signal
|
|
- emit loginFailed(socket);
|
|
-
|
|
- // return
|
|
- return;
|
|
- }
|
|
-
|
|
- // save last user and last session
|
|
- daemonApp->configuration()->setLastUser(user);
|
|
- daemonApp->configuration()->setLastSession(session);
|
|
- daemonApp->configuration()->save();
|
|
-
|
|
- // emit signal
|
|
- emit loginSucceeded(socket);
|
|
+ connect(m_authenticator, SIGNAL(loginFailed(QLocalSocket*)), this, SIGNAL(loginFailed(QLocalSocket*)));
|
|
+ connect(m_authenticator, SIGNAL(loginSucceeded(QLocalSocket*)), this, SIGNAL(loginSucceeded(QLocalSocket*)));
|
|
+ m_authenticator->start(socket, user, session, password, false);
|
|
+
|
|
+ // save last user and last session FIXME
|
|
+// daemonApp->configuration()->setLastUser(user);
|
|
+// daemonApp->configuration()->setLastSession(session);
|
|
+// daemonApp->configuration()->save();
|
|
}
|
|
}
|
|
diff --git a/src/daemon/Display.h b/src/daemon/Display.h
|
|
index 9c475a9..5c22f8b 100644
|
|
--- a/src/daemon/Display.h
|
|
+++ b/src/daemon/Display.h
|
|
@@ -21,6 +21,7 @@
|
|
#define SDDM_DISPLAY_H
|
|
|
|
#include <QObject>
|
|
+#include <QtCore/QProcess>
|
|
|
|
class QLocalSocket;
|
|
|
|
@@ -34,17 +35,16 @@ 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();
|
|
|
|
const int displayId() const;
|
|
const int terminalId() const;
|
|
+ QProcessEnvironment sessionEnv(const QString& user) const;
|
|
|
|
const QString &name() const;
|
|
|
|
const QString &cookie() const;
|
|
- const QByteArray rawCookie() const;
|
|
void addCookie(const QString &file);
|
|
|
|
public slots:
|
|
@@ -56,12 +56,10 @@ namespace SDDM {
|
|
signals:
|
|
void stopped();
|
|
|
|
- void loginFailed(QLocalSocket *socket);
|
|
- void loginSucceeded(QLocalSocket *socket);
|
|
+ void loginFailed(QLocalSocket*);
|
|
+ void loginSucceeded(QLocalSocket*);
|
|
|
|
private:
|
|
- void init();
|
|
-
|
|
bool m_relogin { true };
|
|
bool m_started { false };
|
|
|
|
diff --git a/src/daemon/Session.cpp b/src/daemon/Session.cpp
|
|
deleted file mode 100644
|
|
index de86c64..0000000
|
|
--- a/src/daemon/Session.cpp
|
|
+++ /dev/null
|
|
@@ -1,109 +0,0 @@
|
|
-/***************************************************************************
|
|
-* Copyright (c) 2013 Abdurrahman AVCI <abdurrahmanavci@gmail.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 "Session.h"
|
|
-
|
|
-#include "Authenticator.h"
|
|
-#include "Configuration.h"
|
|
-#include "DaemonApp.h"
|
|
-#include "Display.h"
|
|
-
|
|
-#include <QDebug>
|
|
-
|
|
-#include <grp.h>
|
|
-#include <pwd.h>
|
|
-#include <unistd.h>
|
|
-
|
|
-namespace SDDM {
|
|
- Session::Session(const QString &name, QObject *parent) : QProcess(parent), m_name(name) {
|
|
- }
|
|
-
|
|
- const QString &Session::name() const {
|
|
- return m_name;
|
|
- }
|
|
-
|
|
- void Session::setUser(const QString &user) {
|
|
- m_user = user;
|
|
- }
|
|
-
|
|
- void Session::setDir(const QString &dir) {
|
|
- m_dir = dir;
|
|
- }
|
|
-
|
|
- void Session::setUid(int uid) {
|
|
- m_uid = uid;
|
|
- }
|
|
-
|
|
- void Session::setGid(int gid) {
|
|
- m_gid = gid;
|
|
- }
|
|
-
|
|
- void Session::setupChildProcess() {
|
|
- if (daemonApp->configuration()->testing)
|
|
- return;
|
|
-
|
|
- Authenticator *authenticator = qobject_cast<Authenticator *>(parent());
|
|
-
|
|
- if (initgroups(qPrintable(m_user), m_gid)) {
|
|
- qCritical() << " DAEMON: Failed to initialize user groups.";
|
|
-
|
|
- // emit signal
|
|
- emit finished(EXIT_FAILURE, QProcess::NormalExit);
|
|
-
|
|
- // exit
|
|
- exit(EXIT_FAILURE);
|
|
- }
|
|
-
|
|
- if (setgid(m_gid)) {
|
|
- qCritical() << " DAEMON: Failed to set group id.";
|
|
-
|
|
- // emit signal
|
|
- emit finished(EXIT_FAILURE, QProcess::NormalExit);
|
|
-
|
|
- // exit
|
|
- exit(EXIT_FAILURE);
|
|
- }
|
|
-
|
|
- if (setuid(m_uid)) {
|
|
- qCritical() << " DAEMON: Failed to set user id.";
|
|
-
|
|
- // emit signal
|
|
- emit finished(EXIT_FAILURE, QProcess::NormalExit);
|
|
-
|
|
- // exit
|
|
- exit(EXIT_FAILURE);
|
|
-
|
|
- }
|
|
-
|
|
- // add cookie
|
|
- Display *display = qobject_cast<Display *>(authenticator->parent());
|
|
- display->addCookie(QString("%1/.Xauthority").arg(m_dir));
|
|
-
|
|
- // change to user home dir
|
|
- if (chdir(qPrintable(m_dir))) {
|
|
- qCritical() << " DAEMON: Failed to change dir to user home.";
|
|
-
|
|
- // emit signal
|
|
- emit finished(EXIT_FAILURE, QProcess::NormalExit);
|
|
-
|
|
- // exit
|
|
- exit(EXIT_FAILURE);
|
|
- }
|
|
- }
|
|
-}
|
|
diff --git a/src/daemon/Session.h b/src/daemon/Session.h
|
|
deleted file mode 100644
|
|
index 1f075d3..0000000
|
|
--- a/src/daemon/Session.h
|
|
+++ /dev/null
|
|
@@ -1,51 +0,0 @@
|
|
-/***************************************************************************
|
|
-* Copyright (c) 2013 Abdurrahman AVCI <abdurrahmanavci@gmail.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_SESSION_H
|
|
-#define SDDM_SESSION_H
|
|
-
|
|
-#include <QProcess>
|
|
-
|
|
-namespace SDDM {
|
|
- class Session : public QProcess {
|
|
- Q_OBJECT
|
|
- Q_DISABLE_COPY(Session)
|
|
- public:
|
|
- explicit Session(const QString &name, QObject *parent = 0);
|
|
-
|
|
- const QString &name() const;
|
|
-
|
|
- void setUser(const QString &user);
|
|
- void setDir(const QString &dir);
|
|
- void setUid(int uid);
|
|
- void setGid(int gid);
|
|
-
|
|
- protected:
|
|
- void setupChildProcess();
|
|
-
|
|
- private:
|
|
- QString m_name { "" };
|
|
- QString m_user { "" };
|
|
- QString m_dir { "" };
|
|
- int m_uid { 0 };
|
|
- int m_gid { 0 };
|
|
- };
|
|
-}
|
|
-
|
|
-#endif // SDDM_SESSION_H
|
|
diff --git a/src/daemon/xdmcp/Packet.cpp b/src/daemon/xdmcp/Packet.cpp
|
|
deleted file mode 100644
|
|
index 90688d0..0000000
|
|
--- a/src/daemon/xdmcp/Packet.cpp
|
|
+++ /dev/null
|
|
@@ -1,435 +0,0 @@
|
|
-/*
|
|
- * 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
|
|
deleted file mode 100644
|
|
index 507b1b4..0000000
|
|
--- a/src/daemon/xdmcp/Packet.h
|
|
+++ /dev/null
|
|
@@ -1,394 +0,0 @@
|
|
-/*
|
|
- * 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
|
|
deleted file mode 100644
|
|
index edfdff4..0000000
|
|
--- a/src/daemon/xdmcp/Server.cpp
|
|
+++ /dev/null
|
|
@@ -1,149 +0,0 @@
|
|
-/*
|
|
- * 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
|
|
deleted file mode 100644
|
|
index 2898381..0000000
|
|
--- a/src/daemon/xdmcp/Server.h
|
|
+++ /dev/null
|
|
@@ -1,118 +0,0 @@
|
|
-/*
|
|
- * 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
|
|
deleted file mode 100644
|
|
index 92e1d6a..0000000
|
|
--- a/src/daemon/xdmcp/Utils.cpp
|
|
+++ /dev/null
|
|
@@ -1,145 +0,0 @@
|
|
-/*
|
|
- * 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
|
|
deleted file mode 100644
|
|
index 9457ef1..0000000
|
|
--- a/src/daemon/xdmcp/Utils.h
|
|
+++ /dev/null
|
|
@@ -1,93 +0,0 @@
|
|
-/*
|
|
- * 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
|