diff --git a/data/scripts/Xsetup b/data/scripts/Xsetup index 8c7c2aa..4c29d0e 100755 --- a/data/scripts/Xsetup +++ b/data/scripts/Xsetup @@ -1,3 +1,6 @@ #!/bin/sh # Xsetup - run as root before the login dialog appears +# Allow all client connect to the Xorg server. Since our X server is started as +# root, but sessions are started as user. +xhost + diff --git a/src/auth/Auth.cpp b/src/auth/Auth.cpp index ce1fe81..1eed7f7 100644 --- a/src/auth/Auth.cpp +++ b/src/auth/Auth.cpp @@ -65,6 +65,8 @@ namespace DDM { QLocalSocket *socket { nullptr }; QString displayServerCmd; QString sessionPath { }; + Session::Type sessionType { Session::UnknownSession }; + QString sessionFileName { }; QString user { }; QString password { }; QByteArray cookie { }; @@ -72,6 +74,7 @@ namespace DDM { bool greeter { false }; bool singleMode { false }; bool identifyOnly { false }; + bool skipAuth { false }; QProcessEnvironment environment { }; qint64 id { 0 }; static qint64 lastId; @@ -317,6 +320,18 @@ namespace DDM { return d->sessionId; } + Session::Type Auth::sessionType() const { + return d->sessionType; + } + + QString Auth::sessionFileName() const { + return d->sessionFileName; + } + + bool Auth::isSingleMode() const { + return d->singleMode; + } + bool Auth::isActive() const { return d->child->state() != QProcess::NotRunning; } @@ -394,6 +409,14 @@ namespace DDM { } } + void Auth::setSessionType(const Session::Type type) { + d->sessionType = type; + } + + void Auth::setSessionFileName(const QString &fileName) { + d->sessionFileName = fileName; + } + int Auth::tty() const { return d->tty; } @@ -424,6 +447,12 @@ namespace DDM { } } + void Auth::setSkipAuth(bool on) { + if (on != d->skipAuth) { + d->skipAuth = on; + } + } + void Auth::start() { QStringList args; args << QStringLiteral("--socket") << SocketServer::instance()->fullServerName(); @@ -442,6 +471,8 @@ namespace DDM { args << QStringLiteral("--single-mode"); if (d->identifyOnly) args << QStringLiteral("--identify-only"); + if (d->skipAuth) + args << QStringLiteral("--skip-auth"); d->child->start(QStringLiteral("%1/ddm-helper").arg(QStringLiteral(LIBEXEC_INSTALL_DIR)), args); } @@ -453,7 +484,13 @@ namespace DDM { d->child->terminate(); // wait for finished - if (!d->child->waitForFinished(5000)) + // TODO: Cut off the waiting. + // The code will be executed when user trying to start sessions other + // than treeland, which will stop the currentAuth and start a new one. + // This process involves the removal of seatd client, which needs a + // small amount of time to wait. Consider to make this process under + // control. + if (!d->child->waitForFinished(500)) d->child->kill(); } } diff --git a/src/auth/Auth.h b/src/auth/Auth.h index bb8c6d8..5f66480 100644 --- a/src/auth/Auth.h +++ b/src/auth/Auth.h @@ -23,6 +23,7 @@ #include "AuthRequest.h" #include "AuthPrompt.h" +#include "Session.h" #include #include @@ -97,12 +98,15 @@ namespace DDM { bool isGreeter() const; bool verbose() const; bool identifyOnly() const; + bool isSingleMode() const; const QByteArray &cookie() const; const QString &user() const; const QString &session() const; const QString &password() const; AuthRequest *request(); QString sessionId() const; + Session::Type sessionType() const; + QString sessionFileName() const; int tty() const; void setTTY(int tty); @@ -146,6 +150,8 @@ namespace DDM { void setVerbose(bool on = true); void setIdentifyOnly(bool on = false); + + void setSkipAuth(bool on = true); /** * Sets the user which will then authenticate * @param user username @@ -179,7 +185,11 @@ namespace DDM { */ void setSingleMode(bool on = true); - void setSessionId(const QString& sessionId); + void setSessionId(const QString &sessionId); + + void setSessionType(const Session::Type type); + + void setSessionFileName(const QString &fileName); public Q_SLOTS: /** diff --git a/src/daemon/Display.cpp b/src/daemon/Display.cpp index fcef17d..2819d74 100644 --- a/src/daemon/Display.cpp +++ b/src/daemon/Display.cpp @@ -590,11 +590,13 @@ namespace DDM { } auth->setUser(user); + auth->setSessionType(session.type()); + auth->setSessionFileName(session.fileName()); if (m_reuseSessionId.isNull()) { auth->setSession(session.exec()); } auth->insertEnvironment(env); - auth->setSingleMode(m_displayServerType == DisplayServerType::SingleCompositerServerType); + auth->setSingleMode(session.isSingleMode()); auth->start(); } @@ -634,22 +636,61 @@ namespace DDM { else stateConfig.Last.User.setDefault(); if (mainConfig.Users.RememberLastSession.get()) - stateConfig.Last.Session.set(auth->session()); + stateConfig.Last.Session.set(auth->sessionFileName()); else stateConfig.Last.Session.setDefault(); stateConfig.save(); - if (m_displayServerType == DisplayServerType::SingleCompositerServerType) { + if (auth->isSingleMode()) { auto* server = reinterpret_cast(m_displayServer); server->onLoginSucceeded(user); + switchToUser(auth->user()); } else { if (m_socket) { emit loginSucceeded(m_socket, user); daemonApp->displayManager()->setLastSession(auth->sessionId()); } - } + if (auth->identifyOnly()) + return; - switchToUser(auth->user()); + // Stop the original suit of displayServer since it has finished its job. + disconnect(m_displayServer, &DisplayServer::stopped, this, &Display::stop); + m_displayServer->stop(); + delete m_displayServer; + m_greeter->stop(); + delete m_greeter; + m_currentAuth->stop(); + m_socketServer->stop(); + delete m_socketServer; + + // Start the target displayServer + m_terminalId = m_sessionTerminalId = fetchAvailableVt(); + m_started = false; + + if (auth->sessionType() == Session::X11Session) { + m_displayServer = new XorgDisplayServer(this); + m_displayServerType = X11DisplayServerType; + } else { + m_displayServer = new WaylandDisplayServer(this); + m_displayServerType = WaylandDisplayServerType; + } + connect(m_displayServer, &DisplayServer::started, this, &Display::displayServerStarted); + connect(m_displayServer, &DisplayServer::stopped, this, &Display::stop); + + m_socketServer = new SocketServer(this); + + // The greeter here is used to start user session. + m_greeter = new Greeter(this); + m_greeter->setDisplayServerCommand(auth->session()); + m_greeter->setUser(user); + m_greeter->setSkipAuth(); + + connect(m_greeter, &Greeter::failed, this, &Display::stop); + connect(m_greeter, &Greeter::displayServerFailed, this, &Display::displayServerFailed); + connect(m_greeter, &Greeter::succeed, this, &Display::stop); + + m_displayServer->start(); + } } m_socket = nullptr; } @@ -711,7 +752,8 @@ namespace DDM { } } - if (status != Auth::HELPER_AUTH_ERROR && m_displayServerType != DisplayServerType::SingleCompositerServerType) + // Don't restart display when ddm-helper crashed (exit code 9) + if (status != Auth::HELPER_AUTH_ERROR && status != Auth::HelperExitStatus(9) && m_displayServerType != DisplayServerType::SingleCompositerServerType) stop(); } @@ -730,7 +772,7 @@ namespace DDM { void Display::slotSessionStarted(bool success) { qDebug() << "Session started" << success; Auth* auth = qobject_cast(sender()); - if (m_displayServerType == SingleCompositerServerType) { + if (auth->isSingleMode()) { switchToUser(auth->user()); } diff --git a/src/daemon/Greeter.cpp b/src/daemon/Greeter.cpp index 916fa36..d56dcdb 100644 --- a/src/daemon/Greeter.cpp +++ b/src/daemon/Greeter.cpp @@ -83,6 +83,14 @@ namespace DDM { m_singleMode = on; } + void Greeter::setUser(const QString &user) { + m_user = user; + } + + void Greeter::setSkipAuth(bool on) { + m_skipAuth = on; + } + void Greeter::setUserActivated(bool active) { m_userActivated = active; } @@ -226,7 +234,8 @@ namespace DDM { if (m_display->displayServerType() == Display::X11DisplayServerType) { env.insert(QStringLiteral("DISPLAY"), m_display->name()); env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("xcb")); - m_auth->setCookie(qobject_cast(displayServer)->cookie()); + if (m_display->sessionType() == "x11") + m_auth->setCookie(qobject_cast(displayServer)->cookie()); } else if (m_display->displayServerType() == Display::WaylandDisplayServerType) { env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("wayland")); env.insert(QStringLiteral("QT_WAYLAND_SHELL_INTEGRATION"), QStringLiteral("fullscreen-shell-v1")); @@ -240,7 +249,7 @@ namespace DDM { qDebug() << "Greeter starting..."; // start greeter - m_auth->setUser(QStringLiteral("dde")); + m_auth->setUser(m_user); QString displayServerCmd = m_displayServerCmd; if (m_singleMode) { displayServerCmd += " --lockscreen"; @@ -255,6 +264,10 @@ namespace DDM { return true; } + if (m_skipAuth) { + m_auth->setSkipAuth(); + } + m_auth->start(); m_tryTimer->start(); @@ -371,6 +384,8 @@ namespace DDM { Q_EMIT ttyFailed(); } else if (status == Auth::HELPER_SESSION_ERROR) { Q_EMIT failed(); + } else if (status == Auth::HELPER_SUCCESS) { + Q_EMIT succeed(); } } diff --git a/src/daemon/Greeter.h b/src/daemon/Greeter.h index ed4e3a6..235d3a8 100644 --- a/src/daemon/Greeter.h +++ b/src/daemon/Greeter.h @@ -42,6 +42,8 @@ namespace DDM { void setSocket(const QString &socket); void setTheme(const QString &theme); void setSingleMode(bool on = true); + void setUser(const QString &user); + void setSkipAuth(bool on = true); void setUserActivated(bool active); QString displayServerCommand() const; @@ -67,6 +69,7 @@ namespace DDM { void ttyFailed(); void failed(); void displayServerFailed(); + void succeed(); void greeterStarted(); private: @@ -75,6 +78,8 @@ namespace DDM { bool m_userActivated { false }; int m_currentRetry { 0 }; int m_maxRetry{ 3 }; + QString m_user = QStringLiteral("dde"); + bool m_skipAuth { false }; Display * const m_display { nullptr }; QString m_socket; diff --git a/src/helper/HelperApp.cpp b/src/helper/HelperApp.cpp index 380bbde..bfc233a 100644 --- a/src/helper/HelperApp.cpp +++ b/src/helper/HelperApp.cpp @@ -123,6 +123,10 @@ namespace DDM { m_backend->setIdentifyOnly(true); } + if ((pos = args.indexOf(QStringLiteral("--skip-auth"))) >= 0) { + m_skipAuth = true; + } + if (server.isEmpty() || m_id <= 0) { qCritical() << "This application is not supposed to be executed manually"; exit(Auth::HELPER_OTHER_ERROR); @@ -163,7 +167,7 @@ namespace DDM { } Q_ASSERT(getuid() == 0); - if (!m_backend->authenticate()) { + if (!m_skipAuth && !m_backend->authenticate()) { authenticated(QString()); // write failed login to btmp diff --git a/src/helper/HelperApp.h b/src/helper/HelperApp.h index 5b948a9..8db81a5 100644 --- a/src/helper/HelperApp.h +++ b/src/helper/HelperApp.h @@ -67,6 +67,7 @@ namespace DDM { QString m_user { }; // TODO: get rid of this in a nice clean way along the way with moving to user session X server QByteArray m_cookie { }; + bool m_skipAuth = false; /*! \brief Write utmp/wtmp/btmp records when a user logs in diff --git a/src/helper/UserSession.cpp b/src/helper/UserSession.cpp index 03c673c..a2c005d 100644 --- a/src/helper/UserSession.cpp +++ b/src/helper/UserSession.cpp @@ -122,14 +122,9 @@ namespace DDM { } qInfo() << "Starting X11 session:" << m_displayServerCmd << command; - if (m_displayServerCmd.isEmpty()) { - auto args = QProcess::splitCommand(command); - setProgram(args.takeFirst()); - setArguments(args); - } else { - setProgram(QStringLiteral(LIBEXEC_INSTALL_DIR "/ddm-helper-start-x11user")); - setArguments({m_displayServerCmd, command}); - } + auto args = QProcess::splitCommand(m_displayServerCmd); + setProgram(args.takeFirst()); + setArguments(args); QProcess::start(); } else if (env.value(QStringLiteral("XDG_SESSION_TYPE")) == QLatin1String("wayland")) { @@ -238,7 +233,7 @@ namespace DDM { // take control of the tty if (takeControl) { - if (ioctl(STDIN_FILENO, TIOCSCTTY, 0) < 0) { + if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0) { const auto error = strerror(errno); qCritical().nospace() << "Failed to take control of " << ttyString << " (" << QFileInfo(ttyString).owner() << "): " << error; _exit(Auth::HELPER_TTY_ERROR);