Use QAuth for authentication
Now that SDDM includes QAuth we can take advantage of its improved authentication support. This is based on PR #155 by Martin Bříza <mbriza@redhat.com>
This commit is contained in:
parent
dba8027899
commit
17e31aaef0
@ -125,6 +125,8 @@ set(DATA_INSTALL_DIR "${CMAKE_INSTALL_FULL_DATADIR}/sddm"
|
||||
set(DBUS_CONFIG_DIR "${CMAKE_INSTALL_SYSCONFDIR}/dbus-1/system.d" CACHE PATH "DBus config files directory")
|
||||
set(STATE_DIR "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/sddm" CACHE PATH "State directory")
|
||||
|
||||
set(SESSION_COMMAND "${DATA_INSTALL_DIR}/scripts/Xsession" CACHE PATH "Script to execute when starting the desktop session")
|
||||
|
||||
set(CONFIG_FILE "${CMAKE_INSTALL_FULL_SYSCONFDIR}/sddm.conf" CACHE PATH "Path of the sddm config file")
|
||||
set(LOG_FILE "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/log/sddm.log" CACHE PATH "Path of the sddm log file")
|
||||
set(COMPONENTS_TRANSLATION_DIR "${DATA_INSTALL_DIR}/translations" CACHE PATH "Components translations directory")
|
||||
|
@ -70,7 +70,7 @@ All options are configured in the [General] section:
|
||||
|
||||
`SessionCommand=`
|
||||
Path of script to execute when starting the desktop session.
|
||||
Default value is "@DATA_INSTALL_DIR@/scripts/Xsession".
|
||||
Default value is "@SESSION_COMMAND@".
|
||||
|
||||
`FacesDir=`
|
||||
Path of the directory containing face files,
|
||||
|
@ -35,7 +35,7 @@ LastSession=
|
||||
RememberLastSession=true
|
||||
|
||||
# Path of script to execute when starting the desktop session
|
||||
SessionCommand=${DATA_INSTALL_DIR}/scripts/Xsession
|
||||
SessionCommand=@SESSION_COMMAND@
|
||||
|
||||
# Path of the directory containing face files
|
||||
# Face files should be in username.face.icon format
|
||||
|
@ -9,7 +9,6 @@ set(DAEMON_SOURCES
|
||||
common/Configuration.cpp
|
||||
common/SafeDataStream.cpp
|
||||
common/SocketWriter.cpp
|
||||
daemon/Authenticator.cpp
|
||||
daemon/DaemonApp.cpp
|
||||
daemon/Display.cpp
|
||||
daemon/DisplayManager.cpp
|
||||
|
@ -28,9 +28,9 @@
|
||||
#define COMPONENTS_TRANSLATION_DIR "@COMPONENTS_TRANSLATION_DIR@"
|
||||
#define STATE_DIR "@STATE_DIR@"
|
||||
|
||||
#define SESSION_COMMAND "@SESSION_COMMAND@"
|
||||
|
||||
#define CONFIG_FILE "@CONFIG_FILE@"
|
||||
#define LOG_FILE "@LOG_FILE@"
|
||||
|
||||
#define QAUTH_XSESSION_PATH "/etc/X11/xinit/Xsession"
|
||||
|
||||
#endif // SDDM_CONSTANTS_H
|
||||
|
@ -1,463 +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 "Authenticator.h"
|
||||
|
||||
#include "Configuration.h"
|
||||
#include "DaemonApp.h"
|
||||
#include "Display.h"
|
||||
#include "DisplayManager.h"
|
||||
#include "Seat.h"
|
||||
#include "Session.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
#ifdef USE_PAM
|
||||
#include <security/pam_appl.h>
|
||||
#else
|
||||
#include <crypt.h>
|
||||
#include <shadow.h>
|
||||
#endif
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
*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(Display *parent) : QObject(parent), m_display(parent) {
|
||||
}
|
||||
|
||||
Authenticator::~Authenticator() {
|
||||
stop();
|
||||
#ifdef USE_PAM
|
||||
delete m_pam;
|
||||
#endif
|
||||
}
|
||||
|
||||
Display *Authenticator::display() const {
|
||||
return m_display;
|
||||
}
|
||||
|
||||
bool Authenticator::start(const QString &user, const QString &session) {
|
||||
return doStart(user, QString(), session, true);
|
||||
}
|
||||
|
||||
bool Authenticator::start(const QString &user, const QString &password, const QString &session) {
|
||||
return doStart(user, password, session, false);
|
||||
}
|
||||
|
||||
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 xdgSessionName = "";
|
||||
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);
|
||||
|
||||
// Desktop names, change the separator
|
||||
if (line.startsWith("DesktopNames=")) {
|
||||
xdgSessionName = line.mid(13);
|
||||
xdgSessionName.replace(';', ':');
|
||||
}
|
||||
}
|
||||
|
||||
// close file
|
||||
file.close();
|
||||
}
|
||||
|
||||
// remove extension
|
||||
sessionName = session.left(session.lastIndexOf("."));
|
||||
} else {
|
||||
command = session;
|
||||
sessionName = session;
|
||||
}
|
||||
|
||||
if (command.isEmpty()) {
|
||||
// log error
|
||||
qCritical() << "Failed to find command for session:" << session;
|
||||
|
||||
// return fail
|
||||
return false;
|
||||
}
|
||||
|
||||
// get display and display
|
||||
Seat *seat = m_display->seat();
|
||||
|
||||
#ifdef USE_PAM
|
||||
if (m_pam)
|
||||
delete m_pam;
|
||||
|
||||
if (!passwordless)
|
||||
m_pam = new PamService("sddm", user, password, passwordless);
|
||||
else
|
||||
m_pam = new PamService("sddm-autologin", user, password, passwordless);
|
||||
|
||||
if (!m_pam)
|
||||
return false;
|
||||
|
||||
// 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(m_display->name()))) != PAM_SUCCESS)
|
||||
return false;
|
||||
|
||||
// set display name
|
||||
if ((m_pam->result = pam_set_item(m_pam->handle, PAM_XDISPLAY, qPrintable(m_display->name()))) != PAM_SUCCESS)
|
||||
return false;
|
||||
|
||||
// specify session information for logind
|
||||
if ((pam_putenv(m_pam->handle, "XDG_SESSION_CLASS=user")) != PAM_SUCCESS)
|
||||
return false;
|
||||
if ((pam_putenv(m_pam->handle, "XDG_SESSION_TYPE=x11")) != PAM_SUCCESS)
|
||||
return false;
|
||||
if ((pam_putenv(m_pam->handle, qPrintable("XDG_SESSION_DESKTOP=" + xdgSessionName))) != PAM_SUCCESS)
|
||||
return false;
|
||||
|
||||
//set the seat name. This is saves the logind PAM module trying to find it.
|
||||
//The logind pam module is not always able to find it if we have only just started the X server
|
||||
QString pamSeatEnv = "XDG_SEAT=" + seat->name();
|
||||
pam_putenv(m_pam->handle, qPrintable(pamSeatEnv));
|
||||
|
||||
QString pamVtnrEnv = "XDG_VTNR=" + QString::number(m_display->terminalId());
|
||||
pam_putenv(m_pam->handle, qPrintable(pamVtnrEnv));
|
||||
|
||||
// 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() << "Failed to get user entry.";
|
||||
|
||||
// return fail
|
||||
return false;
|
||||
}
|
||||
|
||||
struct spwd *sp;
|
||||
if ((sp = getspnam(pw->pw_name)) == nullptr) {
|
||||
// log error
|
||||
qCritical() << "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(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() << "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()), m_display, 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));
|
||||
|
||||
free(envlist[i]);
|
||||
}
|
||||
free(envlist);
|
||||
#else
|
||||
// we strdup'd the string before in this branch
|
||||
free(mapped);
|
||||
|
||||
// session information
|
||||
env.insert("XDG_SESSION_CLASS", "user");
|
||||
env.insert("XDG_SESSION_TYPE", "x11");
|
||||
env.insert("XDG_SESSION_DESKTOP", xdgSessionName);
|
||||
#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", m_display->name());
|
||||
env.insert("XAUTHORITY", QString("%1/.Xauthority").arg(pw->pw_dir));
|
||||
env.insert("XDG_CURRENT_DESKTOP", xdgSessionName);
|
||||
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(m_display->terminalId()));
|
||||
env.insert("DESKTOP_SESSION", 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() << "Failed to start user session.";
|
||||
|
||||
// return fail
|
||||
return false;
|
||||
}
|
||||
|
||||
// log message
|
||||
qDebug() << "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
|
||||
if (!m_started)
|
||||
return;
|
||||
|
||||
// log message
|
||||
qDebug() << "User session stopping...";
|
||||
|
||||
// terminate process
|
||||
process->terminate();
|
||||
|
||||
// wait for finished
|
||||
if (!process->waitForFinished(5000))
|
||||
process->kill();
|
||||
process->deleteLater();
|
||||
process = nullptr;
|
||||
}
|
||||
|
||||
void Authenticator::finished() {
|
||||
// check flag
|
||||
if (!m_started)
|
||||
return;
|
||||
|
||||
// reset flag
|
||||
m_started = false;
|
||||
|
||||
// log message
|
||||
qDebug() << "User session ended.";
|
||||
|
||||
// unregister from the display manager
|
||||
daemonApp->displayManager()->RemoveSession(process->name());
|
||||
|
||||
// delete session process
|
||||
process->deleteLater();
|
||||
process = nullptr;
|
||||
|
||||
#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);
|
||||
delete m_pam;
|
||||
m_pam = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// emit signal
|
||||
emit stopped();
|
||||
}
|
||||
}
|
@ -1,65 +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_AUTHENTICATOR_H
|
||||
#define SDDM_AUTHENTICATOR_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace SDDM {
|
||||
#ifdef USE_PAM
|
||||
class PamService;
|
||||
#endif
|
||||
class Display;
|
||||
class Session;
|
||||
|
||||
class Authenticator : public QObject {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Authenticator)
|
||||
public:
|
||||
Authenticator(Display *parent);
|
||||
~Authenticator();
|
||||
|
||||
Display *display() const;
|
||||
|
||||
public slots:
|
||||
bool start(const QString &user, const QString &session);
|
||||
bool start(const QString &user, const QString &password, const QString &session);
|
||||
|
||||
void stop();
|
||||
void finished();
|
||||
|
||||
signals:
|
||||
void stopped();
|
||||
|
||||
private:
|
||||
bool doStart(const QString &user, const QString &password, const QString &session, bool passwordless);
|
||||
|
||||
bool m_started { false };
|
||||
Display *m_display { nullptr };
|
||||
|
||||
#ifdef USE_PAM
|
||||
PamService *m_pam { nullptr };
|
||||
#endif
|
||||
|
||||
Session *process { nullptr };
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SDDM_AUTHENTICATOR_H
|
@ -1,4 +1,6 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
* Copyright (c) 2014 Martin Bříza <mbriza@redhat.com>
|
||||
* Copyright (c) 2013 Abdurrahman AVCI <abdurrahmanavci@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -19,9 +21,9 @@
|
||||
|
||||
#include "Display.h"
|
||||
|
||||
#include "Authenticator.h"
|
||||
#include "Configuration.h"
|
||||
#include "DaemonApp.h"
|
||||
#include "DisplayManager.h"
|
||||
#include "DisplayServer.h"
|
||||
#include "Seat.h"
|
||||
#include "SocketServer.h"
|
||||
@ -33,13 +35,14 @@
|
||||
#include <QFile>
|
||||
#include <QTimer>
|
||||
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace SDDM {
|
||||
Display::Display(const int displayId, const int terminalId, Seat *parent) : QObject(parent),
|
||||
m_displayId(displayId), m_terminalId(terminalId),
|
||||
m_authenticator(new Authenticator(this)),
|
||||
m_auth(new QAuth(this)),
|
||||
m_displayServer(new DisplayServer(this)),
|
||||
m_seat(parent),
|
||||
m_socketServer(new SocketServer(this)),
|
||||
@ -47,8 +50,14 @@ namespace SDDM {
|
||||
|
||||
m_display = QString(":%1").arg(m_displayId);
|
||||
|
||||
// restart display after user session ended
|
||||
connect(m_authenticator, SIGNAL(stopped()), this, SLOT(stop()));
|
||||
// respond to authentication requests
|
||||
m_auth->setVerbose(true);
|
||||
connect(m_auth, SIGNAL(requestChanged()), this, SLOT(slotRequestChanged()));
|
||||
connect(m_auth, SIGNAL(authentication(QString,bool)), this, SLOT(slotAuthenticationFinished(QString,bool)));
|
||||
connect(m_auth, SIGNAL(session(bool)), this, SLOT(slotSessionStarted(bool)));
|
||||
connect(m_auth, SIGNAL(finished(bool)), this, SLOT(slotHelperFinished(bool)));
|
||||
connect(m_auth, SIGNAL(info(QString,QAuth::Info)), this, SLOT(slotAuthInfo(QString,QAuth::Info)));
|
||||
connect(m_auth, SIGNAL(error(QString,QAuth::Error)), this, SLOT(slotAuthError(QString,QAuth::Error)));
|
||||
|
||||
// restart display after display server ended
|
||||
connect(m_displayServer, SIGNAL(stopped()), this, SLOT(stop()));
|
||||
@ -168,7 +177,8 @@ namespace SDDM {
|
||||
m_started = true;
|
||||
|
||||
// start session
|
||||
m_authenticator->start(daemonApp->configuration()->autoUser(), daemonApp->configuration()->lastSession());
|
||||
m_auth->setAutologin(true);
|
||||
startAuth(daemonApp->configuration()->autoUser(), QString(), daemonApp->configuration()->lastSession());
|
||||
|
||||
// return
|
||||
return;
|
||||
@ -198,11 +208,6 @@ namespace SDDM {
|
||||
if (!m_started)
|
||||
return;
|
||||
|
||||
// stop user session
|
||||
m_authenticator->blockSignals(true);
|
||||
m_authenticator->stop();
|
||||
m_authenticator->blockSignals(false);
|
||||
|
||||
// stop the greeter
|
||||
m_greeter->stop();
|
||||
|
||||
@ -225,21 +230,133 @@ 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);
|
||||
m_socket = socket;
|
||||
startAuth(user, password, session);
|
||||
}
|
||||
|
||||
// return
|
||||
void Display::startAuth(const QString &user, const QString &password, const QString &session) {
|
||||
QString sessionName;
|
||||
QString xdgSessionName;
|
||||
QString command;
|
||||
|
||||
m_passPhrase = password;
|
||||
|
||||
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);
|
||||
|
||||
// Desktop names, change the separator
|
||||
if (line.startsWith("DesktopNames=")) {
|
||||
xdgSessionName = line.mid(13);
|
||||
xdgSessionName.replace(';', ':');
|
||||
}
|
||||
}
|
||||
|
||||
// close file
|
||||
file.close();
|
||||
}
|
||||
|
||||
// remove extension
|
||||
sessionName = session.left(session.lastIndexOf("."));
|
||||
} else {
|
||||
command = session;
|
||||
sessionName = session;
|
||||
}
|
||||
|
||||
if (command.isEmpty()) {
|
||||
qCritical() << "Failed to find command for session:" << session;
|
||||
return;
|
||||
}
|
||||
|
||||
// save last user and last session
|
||||
daemonApp->configuration()->setLastUser(user);
|
||||
daemonApp->configuration()->setLastSession(session);
|
||||
daemonApp->configuration()->save();
|
||||
// save session desktop file name, we'll use it to set the
|
||||
// last session later, in slotAuthenticationFinished()
|
||||
m_sessionName = session;
|
||||
|
||||
// emit signal
|
||||
emit loginSucceeded(socket);
|
||||
QProcessEnvironment env;
|
||||
env.insert("PATH", daemonApp->configuration()->defaultPath());
|
||||
env.insert("DISPLAY", name());
|
||||
env.insert("XDG_SEAT", seat()->name());
|
||||
env.insert("XDG_SEAT_PATH", daemonApp->displayManager()->seatPath(seat()->name()));
|
||||
env.insert("XDG_SESSION_PATH", daemonApp->displayManager()->sessionPath(QString("Session%1").arg(daemonApp->newSessionId())));
|
||||
env.insert("XDG_VTNR", QString::number(terminalId()));
|
||||
env.insert("DESKTOP_SESSION", sessionName);
|
||||
env.insert("XDG_CURRENT_DESKTOP", xdgSessionName);
|
||||
env.insert("XDG_SESSION_CLASS", "user");
|
||||
env.insert("XDG_SESSION_TYPE", "x11");
|
||||
env.insert("XDG_SESSION_DESKTOP", xdgSessionName);
|
||||
m_auth->insertEnvironment(env);
|
||||
|
||||
m_auth->setUser(user);
|
||||
m_auth->setSession(command);
|
||||
m_auth->start();
|
||||
}
|
||||
|
||||
void Display::slotAuthenticationFinished(const QString &user, bool success) {
|
||||
if (success) {
|
||||
qDebug() << "Authenticated successfully";
|
||||
|
||||
struct passwd *pw = getpwnam(qPrintable(user));
|
||||
if (pw) {
|
||||
addCookie(QString("%1/.Xauthority").arg(pw->pw_dir));
|
||||
chown(qPrintable(QString("%1/.Xauthority").arg(pw->pw_dir)), pw->pw_uid, pw->pw_gid);
|
||||
}
|
||||
|
||||
// save last user and session
|
||||
daemonApp->configuration()->setLastUser(m_auth->user());
|
||||
daemonApp->configuration()->setLastSession(m_sessionName);
|
||||
daemonApp->configuration()->save();
|
||||
|
||||
if (m_socket)
|
||||
emit loginSucceeded(m_socket);
|
||||
} else if (m_socket) {
|
||||
qDebug() << "Authentication failure";
|
||||
emit loginFailed(m_socket);
|
||||
}
|
||||
m_socket = nullptr;
|
||||
}
|
||||
|
||||
void Display::slotAuthInfo(const QString &message, QAuth::Info info) {
|
||||
// TODO: presentable to the user, eventually
|
||||
Q_UNUSED(info);
|
||||
qWarning() << "Authentication information:" << message;
|
||||
}
|
||||
|
||||
void Display::slotAuthError(const QString &message, QAuth::Error error) {
|
||||
// TODO: presentable to the user, eventually
|
||||
Q_UNUSED(error);
|
||||
qWarning() << "Authentication error:" << message;
|
||||
}
|
||||
|
||||
void Display::slotHelperFinished(bool success) {
|
||||
stop();
|
||||
}
|
||||
|
||||
void Display::slotRequestChanged() {
|
||||
if (m_auth->request()->prompts().length() == 1) {
|
||||
m_auth->request()->prompts()[0]->setResponse(qPrintable(m_passPhrase));
|
||||
m_auth->request()->done();
|
||||
} else if (m_auth->request()->prompts().length() == 2) {
|
||||
m_auth->request()->prompts()[0]->setResponse(qPrintable(m_auth->user()));
|
||||
m_auth->request()->prompts()[1]->setResponse(qPrintable(m_passPhrase));
|
||||
m_auth->request()->done();
|
||||
}
|
||||
}
|
||||
|
||||
void Display::slotSessionStarted(bool success) {
|
||||
qDebug() << "Session started";
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
* Copyright (c) 2014 Martin Bříza <mbriza@redhat.com>
|
||||
* Copyright (c) 2013 Abdurrahman AVCI <abdurrahmanavci@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -22,6 +24,8 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "qauth/QAuth.h"
|
||||
|
||||
class QLocalSocket;
|
||||
|
||||
namespace SDDM {
|
||||
@ -61,6 +65,8 @@ namespace SDDM {
|
||||
void loginSucceeded(QLocalSocket *socket);
|
||||
|
||||
private:
|
||||
void startAuth(const QString &user, const QString &password, const QString &session);
|
||||
|
||||
bool m_relogin { true };
|
||||
bool m_started { false };
|
||||
|
||||
@ -69,14 +75,24 @@ namespace SDDM {
|
||||
|
||||
QString m_display { ":0" };
|
||||
QString m_cookie { "" };
|
||||
QString m_socket { "" };
|
||||
QString m_authPath { "" };
|
||||
QString m_passPhrase;
|
||||
QString m_sessionName;
|
||||
|
||||
Authenticator *m_authenticator { nullptr };
|
||||
QAuth *m_auth { nullptr };
|
||||
DisplayServer *m_displayServer { nullptr };
|
||||
Seat *m_seat { nullptr };
|
||||
SocketServer *m_socketServer { nullptr };
|
||||
QLocalSocket *m_socket { nullptr };
|
||||
Greeter *m_greeter { nullptr };
|
||||
|
||||
private slots:
|
||||
void slotRequestChanged();
|
||||
void slotAuthenticationFinished(const QString &user, bool success);
|
||||
void slotSessionStarted(bool success);
|
||||
void slotHelperFinished(bool success);
|
||||
void slotAuthInfo(const QString &message, QAuth::Info info);
|
||||
void slotAuthError(const QString &message, QAuth::Error error);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
#include "Session.h"
|
||||
|
||||
#include "Authenticator.h"
|
||||
#include "Configuration.h"
|
||||
#include "DaemonApp.h"
|
||||
#include "Display.h"
|
||||
|
@ -36,7 +36,7 @@ QAuthSession::~QAuthSession() {
|
||||
}
|
||||
|
||||
bool QAuthSession::start() {
|
||||
QProcess::start(QAUTH_XSESSION_PATH, {m_path});
|
||||
QProcess::start(SESSION_COMMAND, {m_path});
|
||||
return waitForStarted();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user