diff --git a/checkpass/checkpass_pam.c b/checkpass/checkpass_pam.c index 3d056f3..10abc21 100644 --- a/checkpass/checkpass_pam.c +++ b/checkpass/checkpass_pam.c @@ -122,6 +122,7 @@ static struct pam_conv PAM_conversation = { #ifdef PAM_FAIL_DELAY static void fail_delay(int retval ATTR_UNUSED, unsigned usec_delay ATTR_UNUSED, void *appdata_ptr ATTR_UNUSED) { + } #endif @@ -134,70 +135,94 @@ AuthReturn Authenticate(const char *method, const char *user, char *(*conv)(Conv char pservb[64]; int pam_error; - openlog("kcheckpass", LOG_PID, LOG_AUTH); + int ret; - PAM_data.conv = conv; - if (strcmp(method, "classic")) { - sprintf(pservb, "%.31s-%.31s", KSCREENSAVER_PAM_SERVICE, method); - pam_service = pservb; - } else { - /* PAM_data.classic = 1; */ - pam_service = KSCREENSAVER_PAM_SERVICE; - } - pam_error = pam_start(pam_service, user, &PAM_conversation, &pamh); - if (pam_error != PAM_SUCCESS) { - return AuthError; - } + ret = pam_start("cutefish", user, &PAM_conversation, &pamh); - tty = ttyname(0); - if (!tty) { - tty = getenv("DISPLAY"); - } + message("%d hello", ret); - pam_error = pam_set_item(pamh, PAM_TTY, tty); - if (pam_error != PAM_SUCCESS) { - pam_end(pamh, pam_error); + if (ret != PAM_SUCCESS) { + message("PAM started failed\n"); return AuthError; } -#ifdef PAM_FAIL_DELAY - pam_set_item(pamh, PAM_FAIL_DELAY, (void *)fail_delay); -#endif - - pam_error = pam_authenticate(pamh, 0); - if (pam_error != PAM_SUCCESS) { - if (PAM_data.abort) { - PAM_data.abort = 0; - pam_end(pamh, pam_error); - return AuthAbort; - } - pam_end(pamh, pam_error); - switch (pam_error) { - case PAM_USER_UNKNOWN: - case PAM_AUTH_ERR: - case PAM_MAXTRIES: /* should handle this better ... */ - case PAM_AUTHINFO_UNAVAIL: /* returned for unknown users ... bogus */ - return AuthBad; - default: - return AuthError; - } + int auth_status = pam_authenticate(pamh, 0); + if (auth_status != PAM_SUCCESS) { + message("Auth Status: %s\n", pam_strerror(pamh, auth_status)); + return AuthError; } - /* just in case some module is stupid enough to ignore a preset PAM_USER */ - pam_error = pam_get_item(pamh, PAM_USER, &pam_item); - if (pam_error != PAM_SUCCESS) { - pam_end(pamh, pam_error); + if (pam_end(pamh, ret) != PAM_SUCCESS) { + message("Failed to terminate PAM\n"); return AuthError; } - if (strcmp((const char *)pam_item, user)) { - pam_end(pamh, PAM_SUCCESS); /* maybe use PAM_AUTH_ERR? */ - return AuthBad; - } - pam_error = pam_setcred(pamh, PAM_REFRESH_CRED); - /* ignore errors on refresh credentials. If this did not work we use the old ones. */ - pam_end(pamh, PAM_SUCCESS); + +// openlog("kcheckpass", LOG_PID, LOG_AUTH); + +// PAM_data.conv = conv; +// if (strcmp(method, "classic")) { +// sprintf(pservb, "%.31s-%.31s", KSCREENSAVER_PAM_SERVICE, method); +// pam_service = pservb; +// } else { +// /* PAM_data.classic = 1; */ +// pam_service = KSCREENSAVER_PAM_SERVICE; +// } +// pam_error = pam_start(pam_service, user, &PAM_conversation, &pamh); +// if (pam_error != PAM_SUCCESS) { +// return AuthError; +// } + +// tty = ttyname(0); +// if (!tty) { +// tty = getenv("DISPLAY"); +// } + +// pam_error = pam_set_item(pamh, PAM_TTY, tty); +// if (pam_error != PAM_SUCCESS) { +// pam_end(pamh, pam_error); +// return AuthError; +// } + +//#ifdef PAM_FAIL_DELAY +// pam_set_item(pamh, PAM_FAIL_DELAY, (void *)fail_delay); +//#endif + +// pam_error = pam_authenticate(pamh, 0); +// if (pam_error != PAM_SUCCESS) { +// if (PAM_data.abort) { +// PAM_data.abort = 0; +// pam_end(pamh, pam_error); +// return AuthAbort; +// } +// pam_end(pamh, pam_error); +// switch (pam_error) { +// case PAM_USER_UNKNOWN: +// case PAM_AUTH_ERR: +// case PAM_MAXTRIES: /* should handle this better ... */ +// case PAM_AUTHINFO_UNAVAIL: /* returned for unknown users ... bogus */ +// return AuthBad; +// default: +// return AuthError; +// } +// } + +// /* just in case some module is stupid enough to ignore a preset PAM_USER */ +// pam_error = pam_get_item(pamh, PAM_USER, &pam_item); +// if (pam_error != PAM_SUCCESS) { +// pam_end(pamh, pam_error); +// return AuthError; +// } +// if (strcmp((const char *)pam_item, user)) { +// pam_end(pamh, PAM_SUCCESS); /* maybe use PAM_AUTH_ERR? */ +// return AuthBad; +// } + +// pam_error = pam_setcred(pamh, PAM_REFRESH_CRED); +// /* ignore errors on refresh credentials. If this did not work we use the old ones. */ + +// pam_end(pamh, PAM_SUCCESS); return AuthOk; } diff --git a/debian/changelog b/debian/changelog index 0068243..132c282 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -cutefish-screenlocker (0.5) UNRELEASED; urgency=high +cutefish-screenlocker (0.5.1-1) UNRELEASED; urgency=high - * Initial release (CutefishOS) + * Update 0.5.1 (CutefishOS) - -- CutefishOS Packaging Team Thu, 16 Sep 2021 02:31:42 +0800 \ No newline at end of file + -- CutefishOS Packaging Team Tue, 12 Oct 2021 09:27:42 +0800 \ No newline at end of file diff --git a/screenlocker/CMakeLists.txt b/screenlocker/CMakeLists.txt index 2b8e62d..c81a6a6 100644 --- a/screenlocker/CMakeLists.txt +++ b/screenlocker/CMakeLists.txt @@ -2,12 +2,15 @@ set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) +include_directories( ${UNIXAUTH_INCLUDE_DIRS} ) + set(PROJECT_SOURCES main.cpp application.cpp authenticator.cpp kcheckpass-enums.h fixx11h.h + pamauthentication.cpp qml.qrc ) @@ -24,6 +27,8 @@ target_link_libraries(cutefish-screenlocker Qt5::Quick ${X11_LIBRARIES} + ${UNIXAUTH_LIBRARIES} + ${SOCKET_LIBRARIES} ) install(TARGETS cutefish-screenlocker RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/screenlocker/application.cpp b/screenlocker/application.cpp index a8adf10..6663f9f 100644 --- a/screenlocker/application.cpp +++ b/screenlocker/application.cpp @@ -64,6 +64,7 @@ public: Application::Application(int &argc, char **argv) : QGuiApplication(argc, argv) , m_authenticator(new Authenticator(AuthenticationMode::Direct, this)) + , m_pam(new PamAuthentication) { // It's a queued connection to give the QML part time to eventually execute code connected to Authenticator::succeeded if any connect(m_authenticator, &Authenticator::succeeded, this, &Application::onSucceeded, Qt::QueuedConnection); @@ -102,6 +103,17 @@ void Application::initialViewSetup() desktopResized(); } +void Application::login(const QString &token) +{ + bool success = m_pam->verify(token); + + if (success) { + onSucceeded(); + } else { + qDebug() << "error"; + } +} + void Application::desktopResized() { const int nScreens = screens().count(); @@ -119,6 +131,7 @@ void Application::desktopResized() // engine stuff QQmlContext *context = view->engine()->rootContext(); context->setContextProperty(QStringLiteral("authenticator"), m_authenticator); + context->setContextProperty(QStringLiteral("App"), this); view->setSource(QUrl("qrc:/qml/LockScreen.qml")); view->setResizeMode(QQuickView::SizeRootObjectToView); @@ -127,13 +140,13 @@ void Application::desktopResized() auto screen = QGuiApplication::screens()[i]; view->setGeometry(screen->geometry()); - if (!m_testing) { - if (QX11Info::isPlatformX11()) { - view->setFlags(Qt::X11BypassWindowManagerHint); - } else { - view->setFlags(Qt::FramelessWindowHint); - } - } +// if (!m_testing) { +// if (QX11Info::isPlatformX11()) { +// view->setFlags(Qt::X11BypassWindowManagerHint); +// } else { +// view->setFlags(Qt::FramelessWindowHint); +// } +// } // overwrite the factory set by kdeclarative // auto oldFactory = view->engine()->networkAccessManagerFactory(); diff --git a/screenlocker/application.h b/screenlocker/application.h index ad18d0e..552e392 100644 --- a/screenlocker/application.h +++ b/screenlocker/application.h @@ -25,6 +25,7 @@ #include #include "authenticator.h" +#include "pamauthentication.h" class Application : public QGuiApplication { @@ -36,6 +37,8 @@ public: void initialViewSetup(); + Q_INVOKABLE void login(const QString &token); + public slots: void desktopResized(); void onScreenAdded(QScreen *screen); @@ -57,6 +60,8 @@ private: Authenticator *m_authenticator; QList m_views; + PamAuthentication *m_pam; + bool m_testing = false; }; diff --git a/screenlocker/authenticator.cpp b/screenlocker/authenticator.cpp index 26f7476..629fa85 100644 --- a/screenlocker/authenticator.cpp +++ b/screenlocker/authenticator.cpp @@ -43,6 +43,7 @@ Authenticator::Authenticator(AuthenticationMode mode, QObject *parent) , m_graceLockTimer(new QTimer(this)) , m_checkPass(nullptr) { + m_pamAuth = new PamAuthentication; m_graceLockTimer->setSingleShot(true); m_graceLockTimer->setInterval(1500); connect(m_graceLockTimer, &QTimer::timeout, this, &Authenticator::graceLockedChanged); diff --git a/screenlocker/authenticator.h b/screenlocker/authenticator.h index 1feac4a..b0d51d6 100644 --- a/screenlocker/authenticator.h +++ b/screenlocker/authenticator.h @@ -21,6 +21,7 @@ along with this program. If not, see . #define AUTHENTICATOR_H #include +#include "pamauthentication.h" class QSocketNotifier; class QTimer; @@ -55,6 +56,8 @@ private: void setupCheckPass(); QTimer *m_graceLockTimer; KCheckPass *m_checkPass; + PamAuthentication *m_pamAuth; + }; class KCheckPass : public QObject @@ -106,6 +109,7 @@ private: int m_fd; bool m_ready = false; AuthenticationMode m_mode; + }; #endif diff --git a/screenlocker/pamauthentication.cpp b/screenlocker/pamauthentication.cpp new file mode 100644 index 0000000..abc0d4d --- /dev/null +++ b/screenlocker/pamauthentication.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2021 CutefishOS Team + * Copyright (C) 2014 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see . + * + * Author : Arto Jalkanen + */ + +#include "pamauthentication.h" +#include + +// PAM +#include + +PamAuthentication::PamAuthentication(QObject *parent) + : QObject(parent) +{ + m_userName = std::getenv("USER"); +} + +bool PamAuthentication::verify(const QString &password) +{ + pam_handle *pamHandle = 0; + + if (!initPam(&pamHandle)) { + qDebug() << Q_FUNC_INFO << "Pam init failed"; + return false; + } + + m_password = password; + + int status = pam_authenticate(pamHandle, 0); + qDebug() << Q_FUNC_INFO << "Pam authenticate status" << status << pam_strerror(pamHandle, status); + if (status == PAM_SUCCESS) { + status = validateAccount(pamHandle); + } + pam_end(pamHandle, status); + + m_password.clear(); + + return status == PAM_SUCCESS; +} + +bool PamAuthentication::initPam(pam_handle **pamHandle) +{ + pam_conv conversation; + conversation.conv = pamConv; + conversation.appdata_ptr = static_cast(this); + + return pam_start("cutefishos", m_userName.toLocal8Bit().data(), + &conversation, pamHandle) == PAM_SUCCESS; +} + +int PamAuthentication::validateAccount(pam_handle *pamHandle) +{ + // This makes sure account and password are still valid + int status = pam_acct_mgmt(pamHandle, 0); + qDebug() << Q_FUNC_INFO << "pam_acct_mgmt: " << status << pam_strerror(pamHandle, status); + // Placeholders for some common errors + // IMPROVE: it'd be good to let user know reason for failure + switch (status) { + case PAM_SUCCESS: + break; + case PAM_USER_UNKNOWN: + break; + case PAM_ACCT_EXPIRED: + break; + case PAM_NEW_AUTHTOK_REQD: + break; + } + return status; +} + +int PamAuthentication::pamConv(int num_msg, const pam_message **msg, pam_response **resp, void *appdata_ptr) +{ + if (num_msg <= 0) { + return PAM_CONV_ERR; + } + + *resp = static_cast(calloc(num_msg, sizeof(pam_response))); + + PamAuthentication *self = static_cast(appdata_ptr); + + for (int count = 0; count < num_msg; ++count) { + switch (msg[count]->msg_style) { + case PAM_PROMPT_ECHO_ON: { + qDebug() << Q_FUNC_INFO << "PAM_PROMPT_ECHO_ON received"; + resp[count]->resp = strdup(self->m_password.toLocal8Bit().data()); + resp[count]->resp_retcode = 0; + break; + } + case PAM_PROMPT_ECHO_OFF: { + qDebug() << Q_FUNC_INFO << "PAM_PROMPT_ECHO_OFF received"; + resp[count]->resp = strdup(self->m_password.toLocal8Bit().data()); + resp[count]->resp_retcode = 0; + break; + } + case PAM_TEXT_INFO: { + QString message(msg[count]->msg); + qDebug() << Q_FUNC_INFO << "PAM_TEXT_INFO received" << message; + break; + } + case PAM_AUTHTOK: { + qDebug() << Q_FUNC_INFO << "PAM_AUTHTOK received"; + break; + } + default: { + qDebug() << Q_FUNC_INFO << "Other PAM msg received: " << msg[count]->msg_style; + } + } + } + + return PAM_SUCCESS; +} diff --git a/screenlocker/pamauthentication.h b/screenlocker/pamauthentication.h new file mode 100644 index 0000000..14197db --- /dev/null +++ b/screenlocker/pamauthentication.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 CutefishOS Team + * Copyright (C) 2014 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see . + * + * Author : Arto Jalkanen + */ + +#ifndef PAMAUTHENTICATION_H +#define PAMAUTHENTICATION_H + +#include + +// Forward declarations +struct pam_handle; +struct pam_message; +struct pam_response; + +class PamAuthentication : public QObject +{ + Q_OBJECT + +public: + explicit PamAuthentication(QObject *parent = nullptr); + + Q_INVOKABLE bool verify(const QString &password); + +private: + bool initPam(pam_handle **pamHandle); + int validateAccount(pam_handle *pamHandle); + static int pamConv(int num_msg, const pam_message **msg, + pam_response **resp, void *appdata_ptr); + +private: + QString m_userName; + QString m_password; +}; + +#endif // PAMAUTHENTICATION_H diff --git a/screenlocker/qml/LockScreen.qml b/screenlocker/qml/LockScreen.qml index c9c360f..207dc9d 100644 --- a/screenlocker/qml/LockScreen.qml +++ b/screenlocker/qml/LockScreen.qml @@ -334,7 +334,9 @@ Item { return } - authenticator.tryUnlock(password.text) + App.login(password.text) + +// authenticator.tryUnlock(password.text) } Timer {