Commit e6d71696 authored by David Edmundson's avatar David Edmundson

initial commit

parents
/*
* Base backend class to be inherited further
* Copyright (C) 2013 Martin B????za <mbriza@redhat.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 "Backend.h"
#include "HelperApp.h"
#include "backend/PamBackend.h"
#include "UserSession.h"
#include <QtCore/QProcessEnvironment>
#include <pwd.h>
namespace SDDM {
Backend *Backend::get(HelperApp* parent)
{
return new PamBackend(parent);
}
Backend::Backend(HelperApp* parent)
: QObject(parent)
, m_app(parent) {
}
void Backend::setAutologin(bool on) {
m_autologin = on;
}
void Backend::setGreeter(bool on) {
m_greeter = on;
}
bool Backend::openSession() {
struct passwd *pw;
pw = getpwnam(qPrintable(qobject_cast<HelperApp*>(parent())->user()));
if (pw) {
QProcessEnvironment env = m_app->session()->processEnvironment();
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);
if (env.contains("DISPLAY") && !env.contains("XAUTHORITY"))
env.insert("XAUTHORITY", QString("%1/.Xauthority").arg(pw->pw_dir));
// TODO: I'm fairly sure this shouldn't be done for PAM sessions, investigate!
m_app->session()->setProcessEnvironment(env);
}
return m_app->session()->start();
}
}
/*
* Base backend class to be inherited further
* Copyright (C) 2013 Martin Bříza <mbriza@redhat.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 BACKEND_H
#define BACKEND_H
#include <QtCore/QObject>
namespace SDDM {
class HelperApp;
class Backend : public QObject
{
Q_OBJECT
public:
/**
* Requests allocation of a new backend instance.
* The method chooses the most suitable one for the current system.
*/
static Backend *get(HelperApp *parent);
void setAutologin(bool on = true);
void setGreeter(bool on = true);
public slots:
virtual bool start(const QString &user = QString()) = 0;
virtual bool authenticate() = 0;
virtual bool openSession();
virtual QString userName() = 0;
protected:
Backend(HelperApp *parent);
HelperApp *m_app;
bool m_autologin { false };
bool m_greeter { false };
};
}
#endif // BACKEND_H
cmake_minimum_required(VERSION 2.8.8)
project(SSSSDDDDDMMMM)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# Silence CMake 3.0 warnings
if(POLICY CMP0043)
cmake_policy(SET CMP0043 OLD)
endif()
find_package(Qt5Core REQUIRED)
find_package(Qt5DBus REQUIRED)
find_package(PAM)
add_definitions(-DUSE_PAM)
add_definitions(-Wall -std=c++11)
include_directories(
"${CMAKE_SOURCE_DIR}/src/common"
"${CMAKE_SOURCE_DIR}/src/auth"
)
include_directories("${CMAKE_BINARY_DIR}/src/common")
set(HELPER_SOURCES
Backend.cpp
HelperApp.cpp
UserSession.cpp
backend/PamHandle.cpp
backend/PamBackend.cpp
)
add_executable(sddm-helper ${HELPER_SOURCES})
target_link_libraries(sddm-helper Qt5::Core ${PAM_LIBRARIES})
# install(TARGETS sddm-helper RUNTIME DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}")
# - Try to find the PAM libraries
# Once done this will define
#
# PAM_FOUND - system has pam
# PAM_INCLUDE_DIR - the pam include directory
# PAM_LIBRARIES - libpam library
if (PAM_INCLUDE_DIR AND PAM_LIBRARY)
# Already in cache, be silent
set(PAM_FIND_QUIETLY TRUE)
endif (PAM_INCLUDE_DIR AND PAM_LIBRARY)
find_path(PAM_INCLUDE_DIR NAMES security/pam_appl.h pam/pam_appl.h)
find_library(PAM_LIBRARY pam)
find_library(DL_LIBRARY dl)
if (PAM_INCLUDE_DIR AND PAM_LIBRARY)
set(PAM_FOUND TRUE)
if (DL_LIBRARY)
set(PAM_LIBRARIES ${PAM_LIBRARY} ${DL_LIBRARY})
else (DL_LIBRARY)
set(PAM_LIBRARIES ${PAM_LIBRARY})
endif (DL_LIBRARY)
if (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h)
# darwin claims to be something special
set(HAVE_PAM_PAM_APPL_H 1)
endif (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h)
if (NOT DEFINED PAM_MESSAGE_CONST)
include(CheckCXXSourceCompiles)
# XXX does this work with plain c?
check_cxx_source_compiles("
#if ${HAVE_PAM_PAM_APPL_H}+0
# include <pam/pam_appl.h>
#else
# include <security/pam_appl.h>
#endif
static int PAM_conv(
int num_msg,
const struct pam_message **msg, /* this is the culprit */
struct pam_response **resp,
void *ctx)
{
return 0;
}
int main(void)
{
struct pam_conv PAM_conversation = {
&PAM_conv, /* this bombs out if the above does not match */
0
};
return 0;
}
" PAM_MESSAGE_CONST)
endif (NOT DEFINED PAM_MESSAGE_CONST)
set(PAM_MESSAGE_CONST ${PAM_MESSAGE_CONST} CACHE BOOL "PAM expects a conversation function with const pam_message")
endif (PAM_INCLUDE_DIR AND PAM_LIBRARY)
if (PAM_FOUND)
if (NOT PAM_FIND_QUIETLY)
message(STATUS "Found PAM: ${PAM_LIBRARIES}")
endif (NOT PAM_FIND_QUIETLY)
else (PAM_FOUND)
if (PAM_FIND_REQUIRED)
message(FATAL_ERROR "PAM was not found")
endif(PAM_FIND_REQUIRED)
endif (PAM_FOUND)
mark_as_advanced(PAM_INCLUDE_DIR PAM_LIBRARY DL_LIBRARY PAM_MESSAGE_CONST)
\ No newline at end of file
/*
* Main authentication application class
* Copyright (C) 2013 Martin B????za <mbriza@redhat.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 "HelperApp.h"
#include "Backend.h"
#include "UserSession.h"
#include <QtCore/QTimer>
#include <QtCore/QFile>
#include <QtCore/QDebug>
#include <QtNetwork/QLocalSocket>
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
namespace SDDM {
HelperApp::HelperApp(int& argc, char** argv)
: QCoreApplication(argc, argv)
, m_backend(Backend::get(this))
, m_session(new UserSession(this))
{
m_backend->setAutologin(true);
setUp());
}
void HelperApp::setUp() {
QStringList args = QCoreApplication::arguments();
QString server;
int pos;
if ((pos = args.indexOf("--id")) >= 0) {
if (pos >= args.length() - 1) {
qCritical() << "This application is not supposed to be executed manually";
exit(Auth::HELPER_OTHER_ERROR);
return;
}
m_id = QString(args[pos + 1]).toLongLong();
}
if ((pos = args.indexOf("--start")) >= 0) {
if (pos >= args.length() - 1) {
qCritical() << "This application is not supposed to be executed manually";
exit(Auth::HELPER_OTHER_ERROR);
return;
}
m_session->setPath(args[pos + 1]);
}
if ((pos = args.indexOf("--user")) >= 0) {
if (pos >= args.length() - 1) {
qCritical() << "This application is not supposed to be executed manually";
exit(Auth::HELPER_OTHER_ERROR);
return;
}
m_user = args[pos + 1];
}
doAuth();
connect(m_session, SIGNAL(finished(int)), this, SLOT(sessionFinished(int)));
m_socket->connectToServer(server, QIODevice::ReadWrite | QIODevice::Unbuffered);
}
void HelperApp::doAuth() {
SafeDataStream str(m_socket);
str << Msg::HELLO << m_id;
str.send();
if (str.status() != QDataStream::Ok)
qCritical() << "Couldn't write initial message:" << str.status();
if (!m_backend->start(m_user)) {
authenticated(QString(""));
exit(Auth::HELPER_AUTH_ERROR);
return;
}
if (!m_backend->authenticate()) {
authenticated(QString(""));
exit(Auth::HELPER_AUTH_ERROR);
return;
}
m_user = m_backend->userName();
QProcessEnvironment env = authenticated(m_user);
if (!m_session->path().isEmpty()) {
env.insert(m_session->processEnvironment());
m_session->setProcessEnvironment(env);
if (!m_backend->openSession()) {
sessionOpened(false);
exit(Auth::HELPER_SESSION_ERROR);
return;
}
sessionOpened(true);
}
else
exit(Auth::HELPER_SUCCESS);
return;
}
void HelperApp::sessionFinished(int status) {
exit(status);
}
QProcessEnvironment HelperApp::authenticated(const QString &user) {
qDebug() << "authenticated";
}
void HelperApp::sessionOpened(bool success) {
qDebug() << "yay, session opened";
}
UserSession *HelperApp::session() {
return m_session;
}
const QString& HelperApp::user() const {
return m_user;
}
HelperApp::~HelperApp() {
}
}
int main(int argc, char** argv) {
SDDM::HelperApp app(argc, argv);
return app.exec();
}
/*
* Main authentication application class
* Copyright (C) 2013 Martin B????za <mbriza@redhat.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 Auth_H
#define Auth_H
#include <QtCore/QCoreApplication>
#include <QtCore/QProcessEnvironment>
namespace SDDM {
class Backend;
class UserSession;
class HelperApp : public QCoreApplication
{
Q_OBJECT
public:
HelperApp(int& argc, char** argv);
virtual ~HelperApp();
UserSession *session();
const QString &user() const;
public slots:
QProcessEnvironment authenticated(const QString &user);
void sessionOpened(bool success);
private slots:
void setUp();
void doAuth();
void sessionFinished(int status);
private:
qint64 m_id { -1 };
Backend *m_backend { nullptr };
UserSession *m_session { nullptr };
QString m_user { };
};
}
#endif // Auth_H
/*
* Session process wrapper
* Copyright (C) 2014 Martin Bříza <mbriza@redhat.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 "Configuration.h"
#include "UserSession.h"
#include "HelperApp.h"
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <fcntl.h>
namespace SDDM {
UserSession::UserSession(HelperApp *parent)
: QProcess(parent) {
}
UserSession::~UserSession() {
}
bool UserSession::start() {
QProcessEnvironment env = qobject_cast<HelperApp*>(parent())->session()->processEnvironment();
if (env.value("XDG_SESSION_CLASS") == "greeter")
QProcess::start(m_path);
else {
qDebug() << "Starting:" << mainConfig.XDisplay.SessionCommand.get()
<< m_path;
QProcess::start(mainConfig.XDisplay.SessionCommand.get(),
QStringList() << m_path);
}
return waitForStarted();
}
void UserSession::setPath(const QString& path) {
m_path = path;
}
QString UserSession::path() const {
return m_path;
}
void UserSession::setupChildProcess() {
const char *username = qobject_cast<HelperApp*>(parent())->user().toLocal8Bit();
struct passwd *pw = getpwnam(username);
if (setgid(pw->pw_gid) != 0) {
qCritical() << "setgid(" << pw->pw_gid << ") failed for user: " << username;
exit(Auth::HELPER_OTHER_ERROR);
}
if (initgroups(pw->pw_name, pw->pw_gid) != 0) {
qCritical() << "initgroups(" << pw->pw_name << ", " << pw->pw_gid << ") failed for user: " << username;
exit(Auth::HELPER_OTHER_ERROR);
}
if (setuid(pw->pw_uid) != 0) {
qCritical() << "setuid(" << pw->pw_uid << ") failed for user: " << username;
exit(Auth::HELPER_OTHER_ERROR);
}
if (chdir(pw->pw_dir) != 0) {
qCritical() << "chdir(" << pw->pw_dir << ") failed for user: " << username;
qCritical() << "verify directory exist and has sufficient permissions";
exit(Auth::HELPER_OTHER_ERROR);
}
//we cannot use setStandardError file as this code is run in the child process
//we want to redirect after we setuid so that .xsession-errors is owned by the user
//swap the stderr pipe of this subprcess into a file .xsession-errors
int fd = ::open(".xsession-errors", O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd >= 0)
{
dup2 (fd, STDERR_FILENO);
::close(fd);
} else {
qWarning() << "Could not open stderr to .xsession-errors file";
}
//redirect any stdout to /dev/null
fd = ::open("/dev/null", O_WRONLY);
if (fd >= 0)
{
dup2 (fd, STDOUT_FILENO);
::close(fd);
} else {
qWarning() << "Could not redirect stdout";
}
QString cookie = qobject_cast<HelperApp*>(parent())->cookie();
if (!cookie.isEmpty()) {
QString file = processEnvironment().value("XAUTHORITY");
QString display = processEnvironment().value("DISPLAY");
qDebug() << "Adding cookie to" << file;
QFile file_handler(file);
file_handler.open(QIODevice::WriteOnly);
file_handler.close();
QString cmd = QString("%1 -f %2 -q").arg(mainConfig.XDisplay.XauthPath.get()).arg(file);
// execute xauth
FILE *fp = popen(qPrintable(cmd), "w");
// check file
if (!fp)
return;
fprintf(fp, "remove %s\n", qPrintable(display));
fprintf(fp, "add %s . %s\n", qPrintable(display), qPrintable(cookie));
fprintf(fp, "exit\n");
// close pipe
pclose(fp);
}
}
}
/*
* Session process wrapper
* Copyright (C) 2014 Martin Bříza <mbriza@redhat.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_AUTH_SESSION_H
#define SDDM_AUTH_SESSION_H
#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtCore/QProcess>
namespace SDDM {
class HelperApp;
class UserSession : public QProcess
{
Q_OBJECT
public:
explicit UserSession(HelperApp *parent);
virtual ~UserSession();
bool start();
void setPath(const QString &path);
QString path() const;
protected:
void setupChildProcess();
private:
QString m_path { };
};
}
#endif // SDDM_AUTH_SESSION_H
This diff is collapsed.
/*
* PAM authentication backend
* Copyright (C) 2013 Martin Bříza <mbriza@redhat.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.
*
*/
#if !defined(PAMBACKEND_H) && defined(USE_PAM)
#define PAMBACKEND_H
// #include "Constants.h"
#include "../Backend.h"
#include <QtCore/QObject>
#include <security/pam_appl.h>
namespace SDDM {
class PamHandle;
class PamBackend;
class PamData {
public:
PamData();
bool insertPrompt(const struct pam_message *msg, bool predict = true);
Auth::Info handleInfo(const struct pam_message *msg, bool predict);
const Request& getRequest() const;
void completeRequest(const Request& request);
QByteArray getResponse(const struct pam_message *msg);
private:
AuthPrompt::Type detectPrompt(const struct pam_message *msg) const;
const Prompt& findPrompt(const struct pam_message *msg) const;
Prompt& findPrompt(const struct pam_message *msg);
bool m_sent { false };
Request m_currentRequest { };
};
class PamBackend : public Backend
{
Q_OBJECT
public:
explicit PamBackend(HelperApp *parent);
virtual ~PamBackend();
int converse(int n, const struct pam_message **msg, struct pam_response **resp);
public slots:
virtual bool start(const QString &user = QString());
virtual bool authenticate();
virtual bool openSession();
virtual QString userName();
private:
PamData *m_data { nullptr };
PamHandle *m_pam { nullptr };
};
}
#endif // PAMBACKEND_H
/*
* PAM API Qt wrapper
* Copyright (C) 2013 Martin Bříza <mbriza@redhat.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 "PamHandle.h"
#include "PamBackend.h"
#include <QtCore/QDebug>
namespace SDDM {
bool PamHandle::putEnv(const QProcessEnvironment& env) {
foreach (const QString& s, env.toStringList()) {
m_result = pam_putenv(m_handle, qPrintable(s));
if (m_result != PAM_SUCCESS) {
qWarning() << "[PAM] putEnv:" << pam_strerror(m_handle, m_result);
return false;
}
}
return true;
}
QProcessEnvironment PamHandle::getEnv() {
QProcessEnvironment env;
// get pam environment
char **envlist = pam_getenvlist(m_handle);