From e6a46089d6f3ffe18be2d1dd421a19dee6c825f8 Mon Sep 17 00:00:00 2001 From: Pier Luigi Fiorini Date: Sat, 7 Jun 2014 12:35:14 +0200 Subject: [PATCH] Make the greeter go through logind Use QAuth for the greeter session so that it will be registered as a logind session with class "greeter". With this, logind can pass drm devices to the greeter, resolving all permission denied errors. This work will also be needed by the Wayland port. From now on we don't support running the greeter as root, however the old code is preserved for test mode. --- services/CMakeLists.txt | 1 + services/sddm-greeter.pam | 17 ++++ src/daemon/Greeter.cpp | 206 ++++++++++++++++++++++++++------------ src/daemon/Greeter.h | 8 ++ 4 files changed, 170 insertions(+), 62 deletions(-) create mode 100644 services/sddm-greeter.pam diff --git a/services/CMakeLists.txt b/services/CMakeLists.txt index 3c88a16..e77e0e6 100644 --- a/services/CMakeLists.txt +++ b/services/CMakeLists.txt @@ -5,3 +5,4 @@ endif() install(FILES sddm.pam DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/pam.d RENAME sddm) install(FILES sddm-autologin.pam DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/pam.d RENAME sddm-autologin) +install(FILES sddm-greeter.pam DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/pam.d RENAME sddm-greeter) diff --git a/services/sddm-greeter.pam b/services/sddm-greeter.pam new file mode 100644 index 0000000..44e209e --- /dev/null +++ b/services/sddm-greeter.pam @@ -0,0 +1,17 @@ +#%PAM-1.0 + +# Load environment from /etc/environment and ~/.pam_environment +auth required pam_env.so + +# Always let the greeter start without authentication +auth required pam_permit.so + +# No action required for account management +account required pam_permit.so + +# Can't change password +password required pam_deny.so + +# Setup session +session required pam_unix.so +session optional pam_systemd.so diff --git a/src/daemon/Greeter.cpp b/src/daemon/Greeter.cpp index b51002a..74829fb 100644 --- a/src/daemon/Greeter.cpp +++ b/src/daemon/Greeter.cpp @@ -22,6 +22,8 @@ #include "Configuration.h" #include "Constants.h" #include "DaemonApp.h" +#include "DisplayManager.h" +#include "Seat.h" #include "Session.h" #include "Display.h" @@ -65,74 +67,115 @@ namespace SDDM { if (!daemonApp->configuration()->testing) { pw = getpwnam(qPrintable("sddm")); - if (!pw) { - qWarning() << "Failed to switch greeter to user sddm. Running greeter as root"; - //continue anyway?? Otherwise we'll block out everyone self compiling - //from logging in + if (pw) { + // take ownership of the socket so we can read/write to it + if (chown(qPrintable(m_socket), pw->pw_uid, pw->pw_gid) == -1) { + qCritical("Couldn't change owner and group to \"%s\": %s", + qPrintable(m_socket), strerror(errno)); + return false; + } + } else { + qCritical() << "Unable to find the sddm user, cannot continue"; + return false; } } - - // create process - m_process = new Session("sddm-greeter", m_display, this); - if (pw) { - m_process->setUser(pw->pw_name); - m_process->setDir(pw->pw_dir); - m_process->setUid(pw->pw_uid); - m_process->setGid(pw->pw_gid); + if (daemonApp->configuration()->testing) { + // create process + m_process = new Session("sddm-greeter", m_display, this); - // take ownership of the socket so we can read/write to it - if (chown(qPrintable(m_socket), pw->pw_uid, pw->pw_gid) == -1) { - qCritical() << "Failed to change owner of socket to user sddm."; + // set user information + if (pw) { + m_process->setUser(pw->pw_name); + m_process->setDir(pw->pw_dir); + m_process->setUid(pw->pw_uid); + m_process->setGid(pw->pw_gid); + } + + // delete process on finish + connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished())); + + connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(onReadyReadStandardOutput())); + connect(m_process, SIGNAL(readyReadStandardError()), SLOT(onReadyReadStandardError())); + + // log message + qDebug() << "Greeter starting..."; + + // set process environment + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("DISPLAY", m_display->name()); + env.insert("XAUTHORITY", m_authPath); + env.insert("XCURSOR_THEME", daemonApp->configuration()->cursorTheme()); + m_process->setProcessEnvironment(env); + + // start greeter + QStringList args; + if (daemonApp->configuration()->testing) + args << "--test-mode"; + args << "--socket" << m_socket + << "--theme" << m_theme; + m_process->start(QString("%1/sddm-greeter").arg(BIN_INSTALL_DIR), args); + + //if we fail to start bail immediately, and don't block in waitForStarted + if (m_process->state() == QProcess::NotRunning) { + qCritical() << "Greeter failed to launch."; + return false; + } + // wait for greeter to start + if (!m_process->waitForStarted()) { + // log message + qCritical() << "Failed to start greeter."; + + // return fail return false; } - } - - // delete process on finish - connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished())); - - connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(onReadyReadStandardOutput())); - connect(m_process, SIGNAL(readyReadStandardError()), SLOT(onReadyReadStandardError())); - - // log message - qDebug() << "Greeter starting..."; - - // set process environment - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - env.insert("DISPLAY", m_display->name()); - env.insert("XAUTHORITY", m_authPath); - env.insert("XCURSOR_THEME", daemonApp->configuration()->cursorTheme()); - m_process->setProcessEnvironment(env); - - // start greeter - QStringList args; - if (daemonApp->configuration()->testing) - args << "--test-mode"; - args << "--socket" << m_socket - << "--theme" << m_theme; - m_process->start(QString("%1/sddm-greeter").arg(BIN_INSTALL_DIR), args); - - //if we fail to start bail immediately, and don't block in waitForStarted - if (m_process->state() == QProcess::NotRunning) { - qCritical() << "Greeter failed to launch."; - return false; - } - // wait for greeter to start - if (!m_process->waitForStarted()) { // log message - qCritical() << "Failed to start greeter."; + qDebug() << "Greeter started."; - // return fail - return false; + // set flag + m_started = true; + } else { + // authentication + m_auth = new QAuth(this); + m_auth->setVerbose(true); + connect(m_auth, SIGNAL(requestChanged()), this, SLOT(onRequestChanged())); + connect(m_auth, SIGNAL(session(bool)), this, SLOT(onSessionStarted(bool))); + connect(m_auth, SIGNAL(finished(bool)), this, SLOT(onHelperFinished(bool))); + connect(m_auth, SIGNAL(info(QString,QAuth::Info)), this, SLOT(authInfo(QString,QAuth::Info))); + connect(m_auth, SIGNAL(error(QString,QAuth::Error)), this, SLOT(authError(QString,QAuth::Error))); + + // greeter command + QStringList args; + args << QString("%1/sddm-greeter").arg(BIN_INSTALL_DIR); + if (daemonApp->configuration()->testing) + args << "--test-mode"; + args << "--socket" << m_socket + << "--theme" << m_theme; + + // greeter environment + QProcessEnvironment env; + env.insert("PATH", daemonApp->configuration()->defaultPath()); + env.insert("DISPLAY", m_display->name()); + env.insert("XAUTHORITY", m_authPath); + env.insert("XCURSOR_THEME", daemonApp->configuration()->cursorTheme()); + env.insert("XDG_SEAT", m_display->seat()->name()); + env.insert("XDG_SEAT_PATH", daemonApp->displayManager()->seatPath(m_display->seat()->name())); + env.insert("XDG_SESSION_PATH", daemonApp->displayManager()->sessionPath(QString("Session%1").arg(daemonApp->newSessionId()))); + env.insert("XDG_VTNR", QString::number(m_display->terminalId())); + env.insert("XDG_SESSION_CLASS", "greeter"); + env.insert("XDG_SESSION_TYPE", "x11"); + m_auth->insertEnvironment(env); + + // log message + qDebug() << "Greeter starting..."; + + // start greeter + m_auth->setUser("sddm"); + m_auth->setSession(args.join(" ")); + m_auth->start(); } - // log message - qDebug() << "Greeter started."; - - // set flag - m_started = true; - // return success return true; } @@ -145,12 +188,14 @@ namespace SDDM { // log message qDebug() << "Greeter stopping..."; - // terminate process - m_process->terminate(); + if (daemonApp->configuration()->testing) { + // terminate process + m_process->terminate(); - // wait for finished - if (!m_process->waitForFinished(5000)) - m_process->kill(); + // wait for finished + if (!m_process->waitForFinished(5000)) + m_process->kill(); + } } void Greeter::finished() { @@ -169,6 +214,33 @@ namespace SDDM { m_process = nullptr; } + void Greeter::onRequestChanged() { + m_auth->request()->setFinishAutomatically(true); + } + + void Greeter::onSessionStarted(bool success) { + // set flag + m_started = success; + + // log message + if (success) + qDebug() << "Greeter session started successfully"; + else + qDebug() << "Greeter session failed to start"; + } + + void Greeter::onHelperFinished(bool success) { + // reset flag + m_started = false; + + // log message + qDebug() << "Greeter stopped."; + + // clean up + m_auth->deleteLater(); + m_auth = nullptr; + } + void Greeter::onReadyReadStandardError() { if (m_process) { @@ -182,4 +254,14 @@ namespace SDDM { qDebug() << "Greeter output:" << qPrintable(m_process->readAllStandardOutput()); } } + + void Greeter::authInfo(const QString &message, QAuth::Info info) { + Q_UNUSED(info); + qDebug() << "Information from greeter session:" << message; + } + + void Greeter::authError(const QString &message, QAuth::Error error) { + Q_UNUSED(error); + qWarning() << "Error from greeter session:" << message; + } } diff --git a/src/daemon/Greeter.h b/src/daemon/Greeter.h index 72773e4..b2c17f7 100644 --- a/src/daemon/Greeter.h +++ b/src/daemon/Greeter.h @@ -22,6 +22,8 @@ #include +#include "qauth/QAuth.h" + namespace SDDM { class Session; class Display; @@ -44,8 +46,13 @@ namespace SDDM { void finished(); private slots: + void onRequestChanged(); + void onSessionStarted(bool success); + void onHelperFinished(bool success); void onReadyReadStandardOutput(); void onReadyReadStandardError(); + void authInfo(const QString &message, QAuth::Info info); + void authError(const QString &message, QAuth::Error error); private: bool m_started { false }; @@ -55,6 +62,7 @@ namespace SDDM { QString m_socket { "" }; QString m_theme { "" }; + QAuth *m_auth { nullptr }; Session *m_process { nullptr }; }; }