File indexing completed on 2024-03-24 05:30:31
0001 /* 0002 SPDX-FileCopyrightText: 2011 Martin Gräßlin <mgraesslin@kde.org> 0003 SPDX-FileCopyrightText: 2023 Harald Sitter <sitter@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 #include <KLocalizedString> 0008 0009 #include <QCommandLineParser> 0010 #include <QDateTime> 0011 #include <QSessionManager> 0012 #include <QSurfaceFormat> 0013 0014 #include <iostream> 0015 0016 #include <signal.h> 0017 0018 #include "greeterapp.h" 0019 0020 #include <config-kscreenlocker.h> 0021 #include <kscreenlocker_greet_logging.h> 0022 0023 #if HAVE_SYS_PRCTL_H 0024 #include <sys/prctl.h> 0025 #endif 0026 #if HAVE_SYS_PROCCTL_H 0027 #include <sys/procctl.h> 0028 #include <unistd.h> 0029 #endif 0030 0031 #include <KSignalHandler> 0032 #include <LayerShellQt/Shell> 0033 0034 static void signalHandler(int signum) 0035 { 0036 ScreenLocker::UnlockApp *instance = qobject_cast<ScreenLocker::UnlockApp *>(QCoreApplication::instance()); 0037 0038 if (!instance) { 0039 return; 0040 } 0041 0042 switch (signum) { 0043 case SIGTERM: 0044 // exit gracefully to not leave behind screensaver processes (bug#224200) 0045 // return exit code 1 to indicate that a valid password was not entered, 0046 // to prevent circumventing the password input by sending a SIGTERM 0047 0048 qCDebug(KSCREENLOCKER_GREET) << "Greeter received SIGTERM. Will exit with error."; 0049 instance->exit(1); 0050 break; 0051 case SIGUSR1: 0052 qCDebug(KSCREENLOCKER_GREET) << "Greeter received SIGUSR1. Will lock immediately."; 0053 instance->lockImmediately(); 0054 break; 0055 } 0056 } 0057 0058 int main(int argc, char *argv[]) 0059 { 0060 LayerShellQt::Shell::useLayerShell(); 0061 0062 // disable ptrace on the greeter 0063 #if HAVE_PR_SET_DUMPABLE 0064 prctl(PR_SET_DUMPABLE, 0); 0065 #endif 0066 #if HAVE_PROC_TRACE_CTL 0067 int mode = PROC_TRACE_CTL_DISABLE; 0068 procctl(P_PID, getpid(), PROC_TRACE_CTL, &mode); 0069 #endif 0070 0071 qCDebug(KSCREENLOCKER_GREET) << "Greeter is starting up."; 0072 0073 KLocalizedString::setApplicationDomain(QByteArrayLiteral("kscreenlocker_greet")); 0074 0075 // explicitly disable input methods on x11 as it makes it impossible to unlock, see BUG 306932 0076 // but explicitly set on screen keyboard such as maliit is allowed 0077 // on wayland, let the compositor take care of the input method 0078 if (!qEnvironmentVariableIsSet("WAYLAND_DISPLAY") && !qEnvironmentVariableIsSet("WAYLAND_SOCKET") 0079 && qgetenv("QT_IM_MODULE") != QByteArrayLiteral("maliit")) { 0080 qputenv("QT_IM_MODULE", QByteArrayLiteral("qtvirtualkeyboard")); 0081 } 0082 0083 // Suppresses modal warnings about unwritable configuration files which may render the system inaccessible 0084 qputenv("KDE_HOME_READONLY", "1"); 0085 // Kwin will re-lock if it restarts, reconnecting would leave us with two greeters but only one functional 0086 qunsetenv("QT_WAYLAND_RECONNECT"); 0087 // Disable QML caching to prevent cache corruption in full or near-full disk scenarios. 0088 // https://bugs.kde.org/show_bug.cgi?id=471952 0089 // https://bugreports.qt.io/browse/QTBUG-117130 0090 qputenv("QML_DISABLE_DISK_CACHE", "1"); 0091 0092 auto format = QSurfaceFormat::defaultFormat(); 0093 format.setOption(QSurfaceFormat::ResetNotification); 0094 QSurfaceFormat::setDefaultFormat(format); 0095 0096 ScreenLocker::UnlockApp app(argc, argv); 0097 0098 KSignalHandler::self()->watchSignal(SIGTERM); 0099 KSignalHandler::self()->watchSignal(SIGUSR1); 0100 0101 // only connect signal handler once we can actual handle the signal properly 0102 QObject::connect(KSignalHandler::self(), &KSignalHandler::signalReceived, &app, &signalHandler); 0103 0104 app.setQuitOnLastWindowClosed(false); 0105 app.setQuitLockEnabled(false); 0106 QCoreApplication::setApplicationName(QStringLiteral("kscreenlocker_greet")); 0107 QCoreApplication::setApplicationVersion(QStringLiteral("0.1")); 0108 QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org")); 0109 0110 // disable session management for the greeter 0111 auto disableSessionManagement = [](QSessionManager &sm) { 0112 sm.setRestartHint(QSessionManager::RestartNever); 0113 }; 0114 QObject::connect(&app, &QGuiApplication::commitDataRequest, disableSessionManagement); 0115 QObject::connect(&app, &QGuiApplication::saveStateRequest, disableSessionManagement); 0116 0117 QCommandLineParser parser; 0118 parser.setApplicationDescription(i18n("Greeter for the KDE Plasma Workspaces Screen locker")); 0119 parser.addHelpOption(); 0120 parser.addVersionOption(); 0121 0122 QCommandLineOption testingOption(QStringLiteral("testing"), i18n("Starts the greeter in testing mode")); 0123 0124 QCommandLineOption themeOption(QStringLiteral("theme"), 0125 i18n("Starts the greeter with the selected theme (only in Testing mode)"), 0126 QStringLiteral("theme"), 0127 QStringLiteral("")); 0128 0129 QCommandLineOption immediateLockOption(QStringLiteral("immediateLock"), i18n("Lock immediately, ignoring any grace time etc.")); 0130 QCommandLineOption graceTimeOption(QStringLiteral("graceTime"), 0131 i18n("Delay till the lock user interface gets shown in milliseconds."), 0132 QStringLiteral("milliseconds"), 0133 QStringLiteral("0")); 0134 QCommandLineOption nolockOption(QStringLiteral("nolock"), i18n("Don't show any lock user interface.")); 0135 QCommandLineOption switchUserOption(QStringLiteral("switchuser"), i18n("Default to the switch user UI.")); 0136 0137 QCommandLineOption waylandFdOption(QStringLiteral("ksldfd"), i18n("File descriptor for connecting to ksld."), QStringLiteral("fd")); 0138 0139 parser.addOption(testingOption); 0140 parser.addOption(themeOption); 0141 parser.addOption(immediateLockOption); 0142 parser.addOption(graceTimeOption); 0143 parser.addOption(nolockOption); 0144 parser.addOption(switchUserOption); 0145 parser.addOption(waylandFdOption); 0146 parser.process(app); 0147 0148 if (parser.isSet(testingOption)) { 0149 app.setTesting(true); 0150 app.setImmediateLock(true); 0151 0152 // parse theme option 0153 const QString theme = parser.value(themeOption); 0154 if (!theme.isEmpty()) { 0155 app.setTheme(theme); 0156 } 0157 0158 // allow ptrace if testing is enabled 0159 #if HAVE_PR_SET_DUMPABLE 0160 prctl(PR_SET_DUMPABLE, 1); 0161 #endif 0162 #if HAVE_PROC_TRACE_CTL 0163 int mode = PROC_TRACE_CTL_ENABLE; 0164 procctl(P_PID, getpid(), PROC_TRACE_CTL, &mode); 0165 #endif 0166 } else { 0167 app.setImmediateLock(parser.isSet(immediateLockOption)); 0168 } 0169 app.setNoLock(parser.isSet(nolockOption)); 0170 0171 bool ok = false; 0172 int graceTime = parser.value(graceTimeOption).toInt(&ok); 0173 if (ok) { 0174 app.setGraceTime(graceTime); 0175 } 0176 0177 if (parser.isSet(switchUserOption)) { 0178 app.setDefaultToSwitchUser(true); 0179 } 0180 0181 if (parser.isSet(waylandFdOption)) { 0182 ok = false; 0183 const int fd = parser.value(waylandFdOption).toInt(&ok); 0184 if (ok) { 0185 app.setKsldSocket(fd); 0186 } 0187 } 0188 0189 app.initialViewSetup(); 0190 0191 // This allow ksmserver to know when the application has actually finished setting itself up. 0192 // Crucial for blocking until it is ready, ensuring locking happens before sleep, e.g. 0193 std::cout << "Locked at " << QDateTime::currentDateTime().toSecsSinceEpoch() << std::endl; 0194 0195 return app.exec(); 0196 }