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.
This commit is contained in:
Pier Luigi Fiorini 2014-06-07 12:35:14 +02:00
parent f84a7fa020
commit e6a46089d6
4 changed files with 170 additions and 62 deletions

View File

@ -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)

17
services/sddm-greeter.pam Normal file
View File

@ -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

View File

@ -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;
}
}

View File

@ -22,6 +22,8 @@
#include <QObject>
#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 };
};
}