diff --git a/REUSE.toml b/REUSE.toml index fea5dab..ed18046 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -69,7 +69,7 @@ SPDX-FileCopyrightText = "None" SPDX-License-Identifier = "GPL-2.0-or-later" [[annotations]] -path = ["releng/prepare-relnotes", "src/daemon/Auth.cpp", "src/daemon/Auth.h", "src/common/ConfigReader.cpp", "src/common/ConfigReader.h", "src/common/Configuration.cpp", "src/common/Configuration.h", "src/common/MessageHandler.h", "src/common/Messages.h", "src/common/Session.cpp", "src/common/Session.h", "src/common/SignalHandler.cpp", "src/common/SignalHandler.h", "src/common/SocketWriter.cpp", "src/common/SocketWriter.h", "src/common/VirtualTerminal.cpp", "src/common/VirtualTerminal.h", "src/common/XAuth.cpp", "src/common/XAuth.h", "src/daemon/DaemonApp.cpp", "src/daemon/DaemonApp.h", "src/daemon/Display.cpp", "src/daemon/Display.h", "src/daemon/DisplayManager.cpp", "src/daemon/DisplayManager.h", "src/daemon/PowerManager.cpp", "src/daemon/PowerManager.h", "src/daemon/SeatManager.cpp", "src/daemon/SeatManager.h", "src/daemon/SocketServer.cpp", "src/daemon/SocketServer.h", "src/daemon/TreelandConnector.cpp", "src/daemon/TreelandConnector.h", "src/daemon/Utils.h", "src/daemon/XorgDisplayServer.cpp", "src/daemon/XorgDisplayServer.h", "src/greeter/GreeterApp.h", "src/greeter/GreeterProxy.cpp", "src/greeter/GreeterProxy.h", "src/greeter/SessionModel.cpp", "src/greeter/SessionModel.h", "src/greeter/UserModel.cpp", "src/greeter/UserModel.h", "src/daemon/UserSession.cpp", "src/daemon/UserSession.h", "src/common/LogindDBusTypes.cpp", "src/common/LogindDBusTypes.h", "src/greeter/GreeterApp.cpp"] +path = ["releng/prepare-relnotes", "src/daemon/Auth.cpp", "src/daemon/Auth.h", "src/common/ConfigReader.cpp", "src/common/ConfigReader.h", "src/common/Configuration.cpp", "src/common/Configuration.h", "src/common/MessageHandler.h", "src/common/Messages.h", "src/common/Session.cpp", "src/common/Session.h", "src/common/SocketWriter.cpp", "src/common/SocketWriter.h", "src/common/VirtualTerminal.cpp", "src/common/VirtualTerminal.h", "src/common/XAuth.cpp", "src/common/XAuth.h", "src/daemon/DaemonApp.cpp", "src/daemon/DaemonApp.h", "src/daemon/Display.cpp", "src/daemon/Display.h", "src/daemon/DisplayManager.cpp", "src/daemon/DisplayManager.h", "src/daemon/PowerManager.cpp", "src/daemon/PowerManager.h", "src/daemon/SeatManager.cpp", "src/daemon/SeatManager.h", "src/daemon/SocketServer.cpp", "src/daemon/SocketServer.h", "src/daemon/TreelandConnector.cpp", "src/daemon/TreelandConnector.h", "src/daemon/Utils.h", "src/daemon/XorgDisplayServer.cpp", "src/daemon/XorgDisplayServer.h", "src/greeter/GreeterApp.h", "src/greeter/GreeterProxy.cpp", "src/greeter/GreeterProxy.h", "src/greeter/SessionModel.cpp", "src/greeter/SessionModel.h", "src/greeter/UserModel.cpp", "src/greeter/UserModel.h", "src/daemon/UserSession.cpp", "src/daemon/UserSession.h", "src/common/LogindDBusTypes.cpp", "src/common/LogindDBusTypes.h", "src/greeter/GreeterApp.cpp"] precedence = "aggregate" SPDX-FileCopyrightText = "None" SPDX-License-Identifier = "GPL-2.0-or-later" diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 7e01138..6227287 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -5,7 +5,6 @@ set(PUBLIC_HEADERS ${CMAKE_SOURCE_DIR}/src/common/MessageHandler.h ${CMAKE_SOURCE_DIR}/src/common/Messages.h ${CMAKE_SOURCE_DIR}/src/common/Session.h - ${CMAKE_SOURCE_DIR}/src/common/SignalHandler.h ${CMAKE_SOURCE_DIR}/src/common/SocketWriter.h ${CMAKE_SOURCE_DIR}/src/common/VirtualTerminal.h ${CMAKE_SOURCE_DIR}/src/common/XAuth.h @@ -17,7 +16,6 @@ set(SRCS ${CMAKE_SOURCE_DIR}/src/common/ConfigReader.cpp ${CMAKE_SOURCE_DIR}/src/common/Configuration.cpp ${CMAKE_SOURCE_DIR}/src/common/Session.cpp - ${CMAKE_SOURCE_DIR}/src/common/SignalHandler.cpp ${CMAKE_SOURCE_DIR}/src/common/SocketWriter.cpp ${CMAKE_SOURCE_DIR}/src/common/VirtualTerminal.cpp ${CMAKE_SOURCE_DIR}/src/common/XAuth.cpp diff --git a/src/common/SignalHandler.cpp b/src/common/SignalHandler.cpp deleted file mode 100644 index 3920c83..0000000 --- a/src/common/SignalHandler.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/*************************************************************************** -* Copyright (c) 2013 Abdurrahman AVCI -* -* 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 "SignalHandler.h" - -#include -#include -#include - -#include -#include -#include - -#include - -namespace DDM { - std::once_flag signalsInitialized; - - int sigintFd[2]; - int sigtermFd[2]; - int sigcustomFd[2]; - - SignalHandler::SignalHandler(QObject *parent) : QObject(parent) { - std::call_once(signalsInitialized, &initialize); - - // If it's done before creating the QCoreApplication, it just will not work - Q_ASSERT(QCoreApplication::instance()); - - snint = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this); - connect(snint, &QSocketNotifier::activated, this, &SignalHandler::handleSigint); - - snterm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this); - connect(snterm, &QSocketNotifier::activated, this, &SignalHandler::handleSigterm); - - sncustom = new QSocketNotifier(sigcustomFd[1], QSocketNotifier::Read, this); - connect(sncustom, &QSocketNotifier::activated, this, &SignalHandler::handleSigCustom); - } - - void SignalHandler::initialize() { - if (::socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sigintFd)) - qCritical() << "Failed to create socket pair for SIGINT handling."; - - struct sigaction sigint = { }; - sigint.sa_handler = SignalHandler::intSignalHandler; - sigemptyset(&sigint.sa_mask); - sigint.sa_flags = SA_RESTART; - - if (sigaction(SIGINT, &sigint, 0) > 0) { - qCritical() << "Failed to set up SIGINT handler."; - return; - } - - if (::socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sigtermFd)) - qCritical() << "Failed to create socket pair for SIGTERM handling."; - - struct sigaction sigterm = { }; - sigterm.sa_handler = SignalHandler::termSignalHandler; - sigemptyset(&sigterm.sa_mask); - sigterm.sa_flags = SA_RESTART; - - if (sigaction(SIGTERM, &sigterm, 0) > 0) { - qCritical() << "Failed to set up SIGTERM handler."; - return; - } - - if (::socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sigcustomFd)) - qCritical() << "Failed to create socket pair for custom signals handling."; - } - - void SignalHandler::addCustomSignal(int signal) - { - struct sigaction sigcustom = { }; - sigcustom.sa_handler = SignalHandler::customSignalHandler; - sigemptyset(&sigcustom.sa_mask); - sigcustom.sa_flags = SA_RESTART; - - if (sigaction(signal, &sigcustom, 0) > 0) { - qCritical() << "Failed to set up " << strsignal(signal) << " handler."; - return; - } - } - - void SignalHandler::intSignalHandler(int) { - char a = 1; - if (::write(sigintFd[0], &a, sizeof(a)) == -1) { - qCritical() << "Error writing to the SIGINT handler"; - return; - } - } - - void SignalHandler::termSignalHandler(int) { - char a = 1; - if (::write(sigtermFd[0], &a, sizeof(a)) == -1) { - qCritical() << "Error writing to the SIGTERM handler"; - return; - } - } - - void SignalHandler::customSignalHandler(int signal) { - if (::write(sigcustomFd[0], &signal, sizeof(signal)) == -1) { - qCritical() << "Error writing to the " << strsignal(signal) << " handler"; - return; - } - } - - void SignalHandler::handleSigint() { - // disable notifier - snint->setEnabled(false); - - // read from socket - char a; - if (::read(sigintFd[1], &a, sizeof(a)) == -1) { - // something went wrong! - qCritical() << "Error reading from the socket"; - return; - } - - // log event - qWarning() << "Signal received: SIGINT"; - - // emit signal - emit sigintReceived(); - - // enable notifier - snint->setEnabled(true); - } - - void SignalHandler::handleSigterm() { - // disable notifier - snterm->setEnabled(false); - - // read from socket - char a; - if (::read(sigtermFd[1], &a, sizeof(a)) == -1) { - // something went wrong! - qCritical() << "Error reading from the socket"; - return; - } - - // log event - qWarning() << "Signal received: SIGTERM"; - - // emit signal - emit sigtermReceived(); - - // enable notifier - snterm->setEnabled(true); - } - - void SignalHandler::handleSigCustom() { - // disable notifier - sncustom->setEnabled(false); - - // read from socket - int signal; - if (::read(sigcustomFd[1], &signal, sizeof(signal)) == -1) { - // something went wrong! - qCritical() << "Error reading from the socket"; - return; - } - - // log event - qWarning() << "Signal received: " << strsignal(signal); - - // emit signal - emit customSignalReceived(signal); - - // enable notifier - sncustom->setEnabled(true); - } - - -} diff --git a/src/common/SignalHandler.h b/src/common/SignalHandler.h deleted file mode 100644 index af8513b..0000000 --- a/src/common/SignalHandler.h +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************** -* Copyright (c) 2013 Abdurrahman AVCI -* -* 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 DDM_SIGNALHANDLER_H -#define DDM_SIGNALHANDLER_H - -#include - -class QSocketNotifier; - -namespace DDM { - class SignalHandler : public QObject { - Q_OBJECT - Q_DISABLE_COPY(SignalHandler) - public: - SignalHandler(QObject *parent = 0); - - void addCustomSignal(int signal); - - signals: - void sighupReceived(); - void sigintReceived(); - void sigtermReceived(); - void customSignalReceived(int signal); - - private slots: - void handleSigint(); - void handleSigterm(); - void handleSigCustom(); - - private: - static void initialize(); - static void intSignalHandler(int unused); - static void termSignalHandler(int unused); - static void customSignalHandler(int unused); - - QSocketNotifier *snint { nullptr }; - QSocketNotifier *snterm { nullptr }; - QSocketNotifier *sncustom { nullptr }; - }; -} -#endif // DDM_SIGNALHANDLER_H diff --git a/src/daemon/Auth.cpp b/src/daemon/Auth.cpp index f825dfc..6d39878 100644 --- a/src/daemon/Auth.cpp +++ b/src/daemon/Auth.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -26,7 +27,7 @@ namespace DDM { struct timeval tv; entry.ut_type = USER_PROCESS; - entry.ut_pid = sessionProcessId; + entry.ut_pid = sessionPid; // ut_line: vt if (tty > 0) @@ -63,7 +64,7 @@ namespace DDM { struct timeval tv; entry.ut_type = DEAD_PROCESS; - entry.ut_pid = sessionProcessId; + entry.ut_pid = sessionPid; // ut_line: vt if (tty > 0) @@ -164,27 +165,24 @@ namespace DDM { Auth::Auth(QObject *parent, QString user) : QObject(parent) , user(user) - , m_session(new UserSession(this)) - , d(new AuthPrivate(this)) { - connect(m_session, - QOverload::of(&QProcess::finished), - this, - &Auth::userProcessFinished); - } + , d(new AuthPrivate(this)) {} Auth::~Auth() { - if (m_session->state() != QProcess::NotRunning) - m_session->stop(); if (sessionOpened) { + delete m_notifier; + if (sessionPid > 0) + kill(sessionPid, SIGTERM); + if (sessionLeaderPid > 0) + kill(sessionLeaderPid, SIGTERM); closeSession(); utmpLogout(); } if (d->handle) { d->ret = pam_end(d->handle, d->ret); if (d->ret != PAM_SUCCESS) - qWarning() << "[Auth] end:" << pam_strerror(d->handle, d->ret); + qWarning() << "[Auth] PAM handle end with error!"; } - qDebug() << "[Auth] Auth for user" << user << "ended."; + qInfo() << "[Auth] Auth for user" << user << "ended."; } #define CHECK_RET_AUTH \ @@ -196,11 +194,11 @@ namespace DDM { bool Auth::authenticate(const QByteArray &secret) { Q_ASSERT(!user.isEmpty()); - qDebug() << "[Auth] Starting..."; + qInfo() << "[Auth] Starting..."; d->ret = pam_start("ddm", user.toLocal8Bit().constData(), &d->conv, &d->handle); CHECK_RET_AUTH - qDebug() << "[Auth] Authenticating user" << user; + qInfo() << "[Auth] Authenticating user" << user; // Set the secret, authenticate, then clear the secret // immediately to avoid leak @@ -209,7 +207,7 @@ namespace DDM { *d->secretPtr = nullptr; CHECK_RET_AUTH - qDebug() << "[Auth] Authenticated."; + qInfo() << "[Auth] Authenticated."; d->ret = pam_acct_mgmt(d->handle, 0); CHECK_RET_AUTH @@ -222,51 +220,109 @@ namespace DDM { QProcessEnvironment env, const QByteArray &cookie) { Q_ASSERT(authenticated); - // Insert necessary environment - struct passwd *pw = getpwnam(qPrintable(user)); - if (pw) { - env.insert(QStringLiteral("HOME"), QString::fromLocal8Bit(pw->pw_dir)); - env.insert(QStringLiteral("PWD"), QString::fromLocal8Bit(pw->pw_dir)); - env.insert(QStringLiteral("SHELL"), QString::fromLocal8Bit(pw->pw_shell)); - env.insert(QStringLiteral("USER"), QString::fromLocal8Bit(pw->pw_name)); - env.insert(QStringLiteral("LOGNAME"), QString::fromLocal8Bit(pw->pw_name)); - } - m_session->setProcessEnvironment(env); - // RUN!!! - m_session->start(command, type, cookie); - if (!m_session->waitForStarted()) { - qWarning() << "[Auth] Failed to start user process."; + int pipefd[2]; + if (pipe(pipefd) == -1) { + qWarning() << "[Auth] pipe failed:" << strerror(errno); return -1; } - sessionOpened = true; - - // cache pid for session end - sessionProcessId = m_session->processId(); - // write successful login to utmp/wtmp - utmpLogin(true); - // Get XDG_SESSION_ID via Logind - OrgFreedesktopLogin1ManagerInterface manager(Logind::serviceName(), - Logind::managerPath(), - QDBusConnection::systemBus()); - auto reply = manager.GetSessionByPID(static_cast(sessionProcessId)); - reply.waitForFinished(); - if (reply.isError()) { - qWarning() << "[Auth] GetSessionByPID:" << reply.error().message(); + + // Here is most safe place to jump VT + VirtualTerminal::jumpToVt(tty, false); + + sessionLeaderPid = fork(); + switch (sessionLeaderPid) { + case -1: { + // Fork failed + qWarning() << "[Auth] fork failed:" << strerror(errno); + close(pipefd[0]); + close(pipefd[1]); return -1; } - QDBusObjectPath path = reply.value(); - OrgFreedesktopLogin1SessionInterface session(Logind::serviceName(), - path.path(), - QDBusConnection::systemBus()); - bool ok; - xdgSessionId = session.property("Id").toInt(&ok); - if (!ok) { - qWarning() << "[Auth] Failed to get XDG_SESSION_ID for user" << user; - return -1; + case 0: { + // Child (session leader) process + close(pipefd[0]); + + // Insert necessary environment + struct passwd *pw = getpwnam(qPrintable(user)); + if (pw) { + env.insert(QStringLiteral("HOME"), QString::fromLocal8Bit(pw->pw_dir)); + env.insert(QStringLiteral("PWD"), QString::fromLocal8Bit(pw->pw_dir)); + env.insert(QStringLiteral("SHELL"), QString::fromLocal8Bit(pw->pw_shell)); + env.insert(QStringLiteral("USER"), QString::fromLocal8Bit(pw->pw_name)); + env.insert(QStringLiteral("LOGNAME"), QString::fromLocal8Bit(pw->pw_name)); + } + + // Open session + auto sessionEnv = openSessionInternal(env); + if (!sessionEnv.has_value()) { + qCritical() << "[SessionLeader] Failed to open session. Exit now."; + exit(1); + } + env = *sessionEnv; + + // Retrieve XDG_SESSION_ID + xdgSessionId = env.value(QStringLiteral("XDG_SESSION_ID")).toInt(); + if (xdgSessionId <= 0) { + qCritical() << "[SessionLeader] Invalid XDG_SESSION_ID from pam_open_session()"; + exit(1); + } + write(pipefd[1], &xdgSessionId, sizeof(int)); + + // RUN!!! + UserSession session(this); + session.setProcessEnvironment(env); + session.start(command, type, cookie); + if (!session.waitForStarted()) { + qCritical() << "[SessionLeader] Failed to start session process. Exit now."; + exit(1); + } + + // Send session PID to parent + sessionPid = session.processId(); + write(pipefd[1], &sessionPid, sizeof(qint64)); + qInfo() << "[SessionLeader] Session started with PID" << sessionPid; + + session.waitForFinished(-1); + + // Handle session end + if (session.exitStatus() == QProcess::CrashExit) { + qCritical() << "[SessionLeader] Session process crashed. Exit now."; + exit(1); + } + qInfo() << "[SessionLeader] Session process finished with exit code" + << session.exitCode() << ". Exiting."; + exit(session.exitCode()); + } + default: { + // Parent process + close(pipefd[1]); + + if (read(pipefd[0], &xdgSessionId, sizeof(int)) < 0) { + qWarning() << "[Auth] Failed to read XDG_SESSION_ID from child process:" << strerror(errno); + close(pipefd[0]); + return -1; + } + if (read(pipefd[0], &sessionPid, sizeof(qint64)) < 0) { + qWarning() << "[Auth] Failed to read session PID from child process:" << strerror(errno); + close(pipefd[0]); + return -1; + } + utmpLogin(true); + + // Monitor child process ends + m_notifier = new QSocketNotifier(pipefd[0], QSocketNotifier::Read); + connect(m_notifier, &QSocketNotifier::activated, this, [this, pipefd] { + close(pipefd[0]); + m_notifier->setEnabled(false); + m_notifier->deleteLater(); + Q_EMIT sessionFinished(); + }); + + sessionOpened = true; + return xdgSessionId; + } } - qDebug() << "[Auth] Session opened with XDG_SESSION_ID =" << xdgSessionId; - return xdgSessionId; } #define CHECK_RET_CLOSE \ @@ -279,7 +335,7 @@ namespace DDM { qWarning() << "[Auth] closeSession: Session was not opened."; return true; } - qDebug() << "[Auth] Closing session for user" << user; + qWarning() << "[Auth] Closing session for user" << user; d->ret = pam_close_session(d->handle, 0); CHECK_RET_CLOSE @@ -288,28 +344,27 @@ namespace DDM { d->ret = pam_setcred(d->handle, PAM_DELETE_CRED); CHECK_RET_CLOSE - qDebug() << "[Auth] Session closed."; + qInfo() << "[Auth] Session closed."; return true; } #define CHECK_RET_OPEN \ if (d->ret != PAM_SUCCESS) { \ qWarning() << "[Auth] openSessionInternal:" << pam_strerror(d->handle, d->ret); \ - return nullptr; \ + return std::nullopt; \ } - char **Auth::openSessionInternal(const QProcessEnvironment &sessionEnv) { - qDebug() << "[Auth] Opening session for user" << user; + std::optional Auth::openSessionInternal(const QProcessEnvironment &sessionEnv) { + qInfo() << "[Auth] Opening session for user" << user; d->ret = pam_setcred(d->handle, PAM_ESTABLISH_CRED); CHECK_RET_OPEN // Set PAM_TTY - QString tty = VirtualTerminal::path(sessionEnv.value(QStringLiteral("XDG_VTNR")).toInt()); - d->ret = pam_set_item(d->handle, PAM_TTY, qPrintable(tty)); + QString vtPath = VirtualTerminal::path(tty); + d->ret = pam_set_item(d->handle, PAM_TTY, qPrintable(vtPath)); CHECK_RET_OPEN // Set PAM_XDISPLAY - QString display = sessionEnv.value(QStringLiteral("DISPLAY")); if (!display.isEmpty()) { d->ret = pam_set_item(d->handle, PAM_XDISPLAY, qPrintable(display)); CHECK_RET_OPEN @@ -326,9 +381,22 @@ namespace DDM { d->ret = pam_open_session(d->handle, 0); CHECK_RET_OPEN - qDebug() << "[Auth] Session opened."; - - return pam_getenvlist(d->handle); + qInfo() << "[Auth] Session opened."; + + // Retrieve env vars in new session + QProcessEnvironment env; + char **envlist = pam_getenvlist(d->handle); + if (envlist) { + for (int i = 0; envlist[i] != nullptr; ++i) { + QString str = QString::fromLocal8Bit(envlist[i]); + int equalPos = str.indexOf('='); + if (equalPos != -1) + env.insert(str.left(equalPos), str.mid(equalPos + 1)); + free(envlist[i]); + } + free(envlist); + } + return env; } } // namespace DDM diff --git a/src/daemon/Auth.h b/src/daemon/Auth.h index 6a31fdd..e050ab1 100644 --- a/src/daemon/Auth.h +++ b/src/daemon/Auth.h @@ -6,8 +6,9 @@ #include "Display.h" -#include -#include +#include +#include +#include namespace DDM { class AuthPrivate; @@ -44,8 +45,11 @@ namespace DDM { /** Logind session ID (the XDG_SESSION_ID env var). Positive values are valid */ int xdgSessionId{ 0 }; - /** PID of the child process. Positive values are valid */ - qint64 sessionProcessId{ 0 }; + /** PID of the session leader. Positive values are valid */ + pid_t sessionLeaderPid{ 0 }; + + /** PID of the session process started by session leader. Positive values are valid */ + qint64 sessionPid{ 0 }; public Q_SLOTS: /** @@ -81,17 +85,15 @@ namespace DDM { * fork() * * @param sessionEnv Environment variables to set for the session - * @return result of pam_getenvlist on success, nullptr on failure + * @return Environs retrieved from pam_getenvlist on success, std::nullopt on failure */ - char **openSessionInternal(const QProcessEnvironment &sessionEnv); + std::optional openSessionInternal(const QProcessEnvironment &sessionEnv); Q_SIGNALS: /** - * Emitted when the user process ends. - * - * @param status Exit code of the user process + * Emitted when the session process ends. */ - void userProcessFinished(int status); + void sessionFinished(); private: /** @@ -106,8 +108,8 @@ namespace DDM { */ void utmpLogout(); - /** The user process */ - UserSession *m_session{ nullptr }; + /** Child process listener */ + QSocketNotifier *m_notifier{ nullptr }; AuthPrivate *d{ nullptr }; }; diff --git a/src/daemon/DaemonApp.cpp b/src/daemon/DaemonApp.cpp index 2edacf7..c70f909 100644 --- a/src/daemon/DaemonApp.cpp +++ b/src/daemon/DaemonApp.cpp @@ -24,7 +24,6 @@ #include "DisplayManager.h" #include "PowerManager.h" #include "SeatManager.h" -#include "SignalHandler.h" #include "TreelandConnector.h" #include "MessageHandler.h" @@ -77,18 +76,10 @@ namespace DDM { connect(m_seatManager, &SeatManager::seatCreated, m_displayManager, &DisplayManager::AddSeat); connect(m_seatManager, &SeatManager::seatRemoved, m_displayManager, &DisplayManager::RemoveSeat); - // create signal handler - m_signalHandler = new SignalHandler(this); - - // quit when SIGINT, SIGTERM received - connect(m_signalHandler, &SignalHandler::sigintReceived, this, &DaemonApp::quit); - connect(m_signalHandler, &SignalHandler::sigtermReceived, this, &DaemonApp::quit); - m_treelandConnector = new TreelandConnector(); // log message qDebug() << "Starting..."; - // initialize seats only after signals are connected m_seatManager->initialize(); } @@ -108,10 +99,6 @@ namespace DDM { return m_seatManager; } - SignalHandler *DaemonApp::signalHandler() const { - return m_signalHandler; - } - TreelandConnector *DaemonApp::treelandConnector() const { return m_treelandConnector; } diff --git a/src/daemon/Display.cpp b/src/daemon/Display.cpp index da5d026..d918bc2 100644 --- a/src/daemon/Display.cpp +++ b/src/daemon/Display.cpp @@ -172,8 +172,7 @@ namespace DDM { return; for (auto *auth : std::as_const(auths)) { - disconnect(auth, &Auth::userProcessFinished, nullptr, nullptr); - daemonApp->displayManager()->RemoveSession(auth->sessionId); + disconnect(auth, &Auth::sessionFinished, nullptr, nullptr); delete auth; } auths.clear(); @@ -338,8 +337,8 @@ namespace DDM { activateSession(auth->user, xdgSessionId); } - connect(auth, &Auth::userProcessFinished, this, [this, auth](int status) { - qWarning() << "Session for user" << auth->user << "finished with status" << status; + connect(auth, &Auth::sessionFinished, this, [this, auth]() { + qWarning() << "Session for user" << auth->user << "finished"; auths.removeAll(auth); daemonApp->displayManager()->RemoveSession(auth->sessionId); delete auth; @@ -355,7 +354,7 @@ namespace DDM { void Display::logout([[maybe_unused]] QLocalSocket *socket, int id) { for (Auth *auth : std::as_const(auths)) { if (auth->xdgSessionId == id) { - disconnect(auth, &Auth::userProcessFinished, nullptr, nullptr); + disconnect(auth, &Auth::sessionFinished, nullptr, nullptr); auths.removeAll(auth); daemonApp->displayManager()->RemoveSession(auth->sessionId); delete auth; @@ -366,20 +365,6 @@ namespace DDM { Logind::managerPath(), QDBusConnection::systemBus()); manager.TerminateSession(QString::number(id)); - QTimer::singleShot(2000, this, [this, id]() { - OrgFreedesktopLogin1ManagerInterface manager(Logind::serviceName(), - Logind::managerPath(), - QDBusConnection::systemBus()); - // Some child processes may linger - // (e.g. gnome-keyring-daemon), kill them to avoid the - // whole session stuck in closing state. Send SIGKILL - // directly may make systemd-logind be left in a bad state - // and cannot handle future login, so send SIGTERM - // instead. - - // TODO: Find out why - manager.KillSession(QString::number(id), "all", 15); - }); } void Display::unlock(QLocalSocket *socket, const QString &user, const QString &password) { diff --git a/src/daemon/UserSession.cpp b/src/daemon/UserSession.cpp index 21f356d..c9732b0 100644 --- a/src/daemon/UserSession.cpp +++ b/src/daemon/UserSession.cpp @@ -128,13 +128,7 @@ namespace DDM { } void UserSession::childModifier() { - // Open session Auth *auth = qobject_cast(parent()); - char **env = auth->openSessionInternal(processEnvironment()); - if (!env) { - qCritical() << "Failed to open PAM session in user session process"; - _exit(1); - } // When the display server is part of the session, we leak the VT into // the session as stdin so that it stays open without races @@ -176,7 +170,6 @@ namespace DDM { } } } - VirtualTerminal::jumpToVt(auth->tty, false); // enter Linux namespaces for (const QString &ns: mainConfig.Namespaces.get()) { @@ -318,17 +311,5 @@ namespace DDM { } else { qWarning() << "Could not redirect stdout"; } - - // We execve manually, to be able to pass the PAM environment - QString program = this->program(); - QStringList args = this->arguments(); - QList c_args; - c_args.push_back(strdup(qPrintable(program))); - for (const QString &arg : args) - c_args.push_back(strdup(qPrintable(arg))); - c_args.push_back(nullptr); - execve(qPrintable(program), c_args.data(), env); - qCritical() << "execve(" << program << ") failed:" << strerror(errno); - exit(1); } }