From 26a70a57ce61d174aeb8f4e64b2859313e024543 Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Tue, 19 Sep 2023 17:29:38 +0300 Subject: [PATCH] kdm: new toy display manager most of the projects in this repo are toys btw Signed-off-by: Ivailo Monev --- CMakeLists.txt | 1 + kdm/CMakeLists.txt | 31 ++++++ kdm/kdm.cpp | 255 +++++++++++++++++++++++++++++++++++++++++++++ kdm/kdm.service | 11 ++ kdm/kdmhelper.cpp | 82 +++++++++++++++ kdm/kdmhelper.h | 34 ++++++ 6 files changed, 414 insertions(+) create mode 100644 kdm/CMakeLists.txt create mode 100644 kdm/kdm.cpp create mode 100644 kdm/kdm.service create mode 100644 kdm/kdmhelper.cpp create mode 100644 kdm/kdmhelper.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c3d334c7..98e84e7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,3 +32,4 @@ macro_optional_add_subdirectory (kfirewall) macro_optional_add_subdirectory (khash) macro_optional_add_subdirectory (kprintjobs) macro_optional_add_subdirectory (plasma-wallpapers) +macro_optional_add_subdirectory (kdm) diff --git a/kdm/CMakeLists.txt b/kdm/CMakeLists.txt new file mode 100644 index 00000000..b33c2082 --- /dev/null +++ b/kdm/CMakeLists.txt @@ -0,0 +1,31 @@ +project(kdm) + +add_definitions(-DKDE_DEFAULT_DEBUG_AREA=1603) + +add_executable(kdm kdm.cpp) +target_link_libraries(kdm + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY} + KDE4::kdeui + KDE4::plasma +) + +install( + TARGETS kdm + DESTINATION ${KDE4_SBIN_INSTALL_DIR} +) + +########### next target ############### + +add_executable(kdmhelper kdmhelper.cpp) +target_link_libraries(kdmhelper + KDE4::kdecore + crypt +) + +install( + TARGETS kdmhelper + DESTINATION ${KDE4_LIBEXEC_INSTALL_DIR} +) + +kde4_install_auth_helper_files(kdmhelper org.kde.kdm.helper) diff --git a/kdm/kdm.cpp b/kdm/kdm.cpp new file mode 100644 index 00000000..77f8a259 --- /dev/null +++ b/kdm/kdm.cpp @@ -0,0 +1,255 @@ +/* This file is part of the KDE project + Copyright (C) 2023 Ivailo Monev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const int s_minimumuid = 1000; +static const QSizeF s_usericonsize = QSizeF(70, 70); + +class KDMBackground : public QGraphicsWidget +{ +public: + KDMBackground(QGraphicsItem *parent = nullptr, Qt::WindowFlags flags = 0); + +protected: + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) final; + +private: + QImage m_background; + QImage m_backgroundscaled; +}; + +KDMBackground::KDMBackground(QGraphicsItem *parent, Qt::WindowFlags flags) + : QGraphicsWidget(parent, flags) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_background = QImage(Plasma::Theme::defaultTheme()->wallpaperPath()); +} + +void KDMBackground::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + const QSize windowsize = size().toSize(); + if (m_backgroundscaled.isNull() || windowsize != m_backgroundscaled.size()) { + m_backgroundscaled = m_background.scaled(windowsize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + } + painter->drawImage(QPoint(0, 0), m_backgroundscaled); +} + +class KDMWindow : public QGraphicsView +{ + Q_OBJECT +public: + KDMWindow(QWidget *parent = nullptr); + ~KDMWindow(); + +private Q_SLOTS: + void slotUserClicked(); + void slotPasswordChanged(const QString &password); + void slotLoginReleased(); + +private: + QGraphicsScene* m_scene; + QGraphicsWidget* m_widget; + QGraphicsLinearLayout* m_layout; + Plasma::Frame* m_frame; + QGraphicsGridLayout* m_framelayout; + QGraphicsWidget* m_userswidget; + QGraphicsLinearLayout* m_userslayout; + Plasma::LineEdit* m_lineedit; + Plasma::PushButton* m_pushbutton; + Plasma::FlashingLabel* m_flashinglabel; + QGraphicsWidget* m_spacer; + Plasma::ComboBox* m_combobox; + QString m_loginname; +}; + +KDMWindow::KDMWindow(QWidget *parent) + : QGraphicsView(parent) +{ + m_scene = new QGraphicsScene(this); + + m_widget = new QGraphicsWidget(); + m_layout = new QGraphicsLinearLayout(Qt::Vertical, m_widget); + m_widget->setLayout(m_layout); + + m_frame = new Plasma::Frame(m_widget); + m_frame->setFrameShadow(Plasma::Frame::Sunken); + m_framelayout = new QGraphicsGridLayout(m_frame); + m_userswidget = new QGraphicsWidget(m_frame); + m_userslayout = new QGraphicsLinearLayout(Qt::Horizontal, m_userswidget); + foreach (const KUser &user, KUser::allUsers()) { + if (user.uid() < s_minimumuid) { + continue; + } + Plasma::IconWidget* userwidget = new Plasma::IconWidget(m_userswidget); + QString usericon = user.faceIconPath(); + if (usericon.isEmpty()) { + usericon = QString::fromLatin1("user-identity"); + } + userwidget->setMinimumIconSize(s_usericonsize); + userwidget->setMaximumIconSize(s_usericonsize); + userwidget->setIcon(usericon); + const QString userloginname = user.loginName(); + QString username = user.property(KUser::FullName); + if (username.isEmpty()) { + username = userloginname; + } + userwidget->setText(username); + userwidget->setProperty("_k_loginname", userloginname); + connect( + userwidget, SIGNAL(clicked()), + this, SLOT(slotUserClicked()) + ); + m_userslayout->addItem(userwidget); + } + m_userswidget->setLayout(m_userslayout); + m_framelayout->addItem(m_userswidget, 0, 0); + m_lineedit = new Plasma::LineEdit(m_frame); + m_lineedit->setClickMessage(i18n("Enter password...")); + m_lineedit->nativeWidget()->setPasswordMode(true); + connect( + m_lineedit, SIGNAL(textChanged(QString)), + this, SLOT(slotPasswordChanged(QString)) + ); + m_framelayout->addItem(m_lineedit, 1, 0); + m_pushbutton = new Plasma::PushButton(m_frame); + m_pushbutton->setText(i18n("Login")); + m_pushbutton->setIcon(KIcon("user-online")); + m_pushbutton->setEnabled(false); + connect( + m_pushbutton, SIGNAL(released()), + this, SLOT(slotLoginReleased()) + ); + m_framelayout->addItem(m_pushbutton, 2, 0); + m_frame->setLayout(m_framelayout); + m_layout->addItem(m_frame); + + m_flashinglabel = new Plasma::FlashingLabel(m_widget); + m_flashinglabel->setAutohide(true); + m_layout->addItem(m_flashinglabel); + + m_spacer = new QGraphicsWidget(m_widget); + m_spacer->setMinimumSize(50, 50); + m_layout->addItem(m_spacer); + m_combobox = new Plasma::ComboBox(m_widget); + QDir dir("/usr/share/xsessions"); + foreach (const QString &entry, dir.entryList(QDir::Files)) { + if (entry.endsWith(".desktop")) { + QSettings desktopsettings("/usr/share/xsessions/" + entry); + const QString sessionname = desktopsettings.string("Desktop Entry/Name"); + const QString sessionexec = desktopsettings.string("Desktop Entry/Exec"); + if (!sessionname.isEmpty() && !sessionexec.isEmpty()) { + const QString sessionicon = desktopsettings.string("Desktop Entry/Icon"); + m_combobox->nativeWidget()->addItem(QIcon::fromTheme(sessionicon), sessionname, sessionexec); + } + } + } + m_layout->addItem(m_combobox); + + m_scene->addItem(m_widget); + m_scene->setBackgroundBrush(QBrush(QImage(Plasma::Theme::defaultTheme()->wallpaperPath()))); + + setScene(m_scene); +} + +KDMWindow::~KDMWindow() +{ +} + +void KDMWindow::slotUserClicked() +{ + Plasma::IconWidget* userwidget = qobject_cast(sender()); + m_loginname = userwidget->property("_k_loginname").toString(); +} + +void KDMWindow::slotPasswordChanged(const QString &password) +{ + m_pushbutton->setEnabled(!password.isEmpty()); +} + +void KDMWindow::slotLoginReleased() +{ + if (m_loginname.isEmpty()) { + m_flashinglabel->flash(i18n("Select user first!")); + kWarning() << "Select user first!"; + return; + } + + if (!KAuthorization::isAuthorized("org.kde.kdm.helper")) { + m_flashinglabel->flash(i18n("Not authorized!")); + kWarning() << "Not authorized!"; + return; + } + + QVariantMap kdmarguments; + kdmarguments.insert("user", m_loginname); + kdmarguments.insert("password", m_lineedit->text()); + int kdmreply = KAuthorization::execute( + "org.kde.kdm.helper", "check", kdmarguments + ); + if (kdmreply != 0) { + m_flashinglabel->flash(i18n("Invalid password!")); + kWarning() << "Invalid password!" << kdmreply; + m_lineedit->setText(QString()); + return; + } + + qDebug() << Q_FUNC_INFO << "password matches"; + kdmarguments.insert("session", m_loginname); + kdmreply = KAuthorization::execute( + "org.kde.kdm.helper", "login", kdmarguments + ); + if (kdmreply != 0) { + m_flashinglabel->flash(i18n("Could not login!")); + kWarning() << "Could not login!" << kdmreply; + m_lineedit->setText(QString()); + } +} + + +int main(int argc, char**argv) +{ + QApplication app(argc, argv); + KDMWindow kdm; + kdm.showMaximized(); + // kdm.show(); + return app.exec(); +} + +#include "kdm.moc" diff --git a/kdm/kdm.service b/kdm/kdm.service new file mode 100644 index 00000000..d8d862de --- /dev/null +++ b/kdm/kdm.service @@ -0,0 +1,11 @@ +[Unit] +Description=Katana Display Manager +After=systemd-user-sessions.service + +[Service] +ExecStart=/usr/sbin/kdm +Restart=always +# BusName=org.freedesktop.DisplayManager + +[Install] +Alias=display-manager.service diff --git a/kdm/kdmhelper.cpp b/kdm/kdmhelper.cpp new file mode 100644 index 00000000..e4bb6f91 --- /dev/null +++ b/kdm/kdmhelper.cpp @@ -0,0 +1,82 @@ +/* This file is part of the KDE project + Copyright (C) 2023 Ivailo Monev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kdmhelper.h" + +#include + +#include +#include +#include +#include + +KDMHelper::KDMHelper(const char* const helper, QObject *parent) + : KAuthorization(helper, parent) +{ +} + +int KDMHelper::check(const QVariantMap ¶meters) +{ + const QByteArray userbytes = parameters.value("user").toByteArray(); + const QByteArray passbytes = parameters.value("password").toByteArray(); + if (userbytes.isEmpty() || passbytes.isEmpty()) { + return KAuthorization::HelperError; + } + + struct passwd* pw = ::getpwnam(userbytes.constData()); + if (!pw) { + kWarning() << "null passwd struct"; + return KAuthorization::HelperError; + } + + QByteArray pw_passwd = pw->pw_passwd; + if (pw_passwd == "x" || pw_passwd == "*") { + if (::lckpwdf() != 0) { + kWarning() << "lckpwdf() failed"; + return KAuthorization::HelperError; + } + ::setspent(); + struct spwd *spw = ::getspnam(userbytes.constData()); + if (!spw) { + kWarning() << "null shadow passwd struct"; + ::endspent(); + ::ulckpwdf(); + return KAuthorization::HelperError; + } + pw_passwd = spw->sp_pwdp; + ::endspent(); + ::ulckpwdf(); + } + if (passbytes == pw_passwd || ::crypt(passbytes.constData(), pw_passwd) == pw_passwd) { + return KAuthorization::NoError; + } + kWarning() << "password does not match"; + return 1; +} + +int KDMHelper::login(const QVariantMap ¶meters) +{ + if (!parameters.contains("user")) { + return KAuthorization::HelperError; + } + + // TODO: + return KAuthorization::NoError; +} + +K_AUTH_MAIN("org.kde.kdm.helper", KDMHelper) diff --git a/kdm/kdmhelper.h b/kdm/kdmhelper.h new file mode 100644 index 00000000..1caa0a7d --- /dev/null +++ b/kdm/kdmhelper.h @@ -0,0 +1,34 @@ +/* This file is part of the KDE project + Copyright (C) 2023 Ivailo Monev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KDMHELPER_H +#define KDMHELPER_H + +#include + +class KDMHelper : public KAuthorization +{ + Q_OBJECT +public: + KDMHelper(const char* const helper, QObject *parent = nullptr); +public Q_SLOTS: + int check(const QVariantMap ¶meters); + int login(const QVariantMap ¶meters); +}; + +#endif // KDMHELPER_H