summaryrefslogtreecommitdiffstats
path: root/kdesktop/lockeng.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kdesktop/lockeng.cpp')
-rw-r--r--kdesktop/lockeng.cpp1049
1 files changed, 1049 insertions, 0 deletions
diff --git a/kdesktop/lockeng.cpp b/kdesktop/lockeng.cpp
new file mode 100644
index 000000000..fc3c9db6e
--- /dev/null
+++ b/kdesktop/lockeng.cpp
@@ -0,0 +1,1049 @@
+//===========================================================================
+//
+// This file is part of the TDE project
+//
+// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
+// Copyright (c) 2012 Timothy Pearson <kb9vqf@pearsoncomputing.net>
+//
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <tdeglobal.h>
+
+#ifdef WITH_TDEHWLIB
+#include <ksslcertificate.h>
+#include <kuser.h>
+#include <tdehardwaredevices.h>
+#include <tdecryptographiccarddevice.h>
+#endif
+
+#include <tdestandarddirs.h>
+#include <tdeapplication.h>
+#include <kservicegroup.h>
+#include <tdesimpleconfig.h>
+#include <kdebug.h>
+#include <tdelocale.h>
+#include <tqfile.h>
+#include <tqtimer.h>
+#include <tqeventloop.h>
+#include <dcopclient.h>
+#include <assert.h>
+
+#include <dmctl.h>
+
+#include <dbus/dbus-shared.h>
+#include <tqdbusdata.h>
+#include <tqdbuserror.h>
+#include <tqdbusmessage.h>
+#include <tqdbusobjectpath.h>
+#include <tqdbusproxy.h>
+
+#include "lockeng.h"
+#include "lockeng.moc"
+#include "kdesktopsettings.h"
+
+#include "xautolock_c.h"
+
+#define SYSTEMD_LOGIN1_SERVICE "org.freedesktop.login1"
+#define SYSTEMD_LOGIN1_MANAGER_IFACE "org.freedesktop.login1.Manager"
+#define SYSTEMD_LOGIN1_SESSION_IFACE "org.freedesktop.login1.Session"
+#define SYSTEMD_LOGIN1_SEAT_IFACE "org.freedesktop.login1.Seat"
+#define SYSTEMD_LOGIN1_PATH "/org/freedesktop/login1"
+
+#define DBUS_CONN_NAME "kdesktop_lock"
+
+extern xautolock_corner_t xautolock_corners[ 4 ];
+bool trinity_lockeng_sak_available = true;
+
+SaverEngineEventHandler *gbl_saverEngineEventHandler = nullptr;
+
+static void sigusr1_handler(int)
+{
+ if (gbl_saverEngineEventHandler)
+ {
+ gbl_saverEngineEventHandler->lockCompleted();
+ }
+}
+
+static void sigusr2_handler(int)
+{
+ if (gbl_saverEngineEventHandler)
+ {
+ gbl_saverEngineEventHandler->lockFullyActivated();
+ }
+}
+
+static void sigttin_handler(int)
+{
+ if (gbl_saverEngineEventHandler)
+ {
+ gbl_saverEngineEventHandler->lockReady();
+ }
+}
+
+SaverEngine::SaverEngine()
+ : TQObject(),
+ KScreensaverIface(),
+ mBlankOnly(false),
+ mNewVTAfterLockEngage(false),
+ mValidCryptoCardInserted(false),
+ mSwitchVTAfterLockEngage(-1),
+ dBusLocal(0),
+ dBusWatch(0),
+ systemdSession(0)
+{
+ // handle SIGUSR1
+ mSignalAction.sa_handler= sigusr1_handler;
+ sigemptyset(&(mSignalAction.sa_mask));
+ sigaddset(&(mSignalAction.sa_mask), SIGUSR1);
+ mSignalAction.sa_flags = 0;
+ sigaction(SIGUSR1, &mSignalAction, 0L);
+
+ // handle SIGUSR2
+ mSignalAction.sa_handler= sigusr2_handler;
+ sigemptyset(&(mSignalAction.sa_mask));
+ sigaddset(&(mSignalAction.sa_mask), SIGUSR2);
+ mSignalAction.sa_flags = 0;
+ sigaction(SIGUSR2, &mSignalAction, 0L);
+
+ // handle SIGTTIN (as custom user signal rather than its inherent meaning)
+ mSignalAction.sa_handler= sigttin_handler;
+ sigemptyset(&(mSignalAction.sa_mask));
+ sigaddset(&(mSignalAction.sa_mask), SIGTTIN);
+ mSignalAction.sa_flags = 0;
+ sigaction(SIGTTIN, &mSignalAction, 0L);
+
+ // Save X screensaver parameters
+ XGetScreenSaver(tqt_xdisplay(), &mXTimeout, &mXInterval, &mXBlanking, &mXExposures);
+
+ // Create event handler thread, event loop and object
+ m_eventHandlerThread = new TQEventLoopThread;
+ m_eventHandlerThread->start();
+ m_saverEngineEventHandler = new SaverEngineEventHandler(this);
+ gbl_saverEngineEventHandler = m_saverEngineEventHandler;
+ m_saverEngineEventHandler->moveToThread(m_eventHandlerThread);
+ connect(this, TQ_SIGNAL(terminateEventHandlerThread()), m_saverEngineEventHandler, TQ_SLOT(terminateThread()));
+ connect(this, TQ_SIGNAL(lockScreenSignal(bool)), m_saverEngineEventHandler, TQ_SLOT(lockScreen(bool)));
+ connect(this, TQ_SIGNAL(activateSaverOrLockSignal(LockType)),
+ m_saverEngineEventHandler, TQ_SLOT(activateSaverOrLock(LockType)));
+
+ mXAutoLock = nullptr;
+ mEnabled = false;
+
+ configure();
+
+ // Prevent kdesktop_lock signals from being handled by the main GUI thread.
+ // Those signals will be handled by m_eventHandlerThread instead
+ //
+ // Make sure to keep this code after the constructor of `m_eventHandlerThread`, so that
+ // the new thread starts with the signals unblocked.
+ sigset_t sigBlockMask;
+ sigemptyset(&sigBlockMask);
+ sigaddset(&sigBlockMask, SIGUSR1);
+ sigaddset(&sigBlockMask, SIGUSR2);
+ sigaddset(&sigBlockMask, SIGTTIN);
+ sigaddset(&sigBlockMask, SIGCHLD);
+ pthread_sigmask(SIG_BLOCK, &sigBlockMask, NULL);
+
+ // Start SAK and lock processes
+ TQTimer::singleShot(0, m_saverEngineEventHandler, TQ_SLOT(restartLockProcess()));
+
+#ifdef WITH_TDEHWLIB
+ // Initialize SmartCard readers
+ TDEGenericDevice *hwdevice;
+ TDEHardwareDevices *hwdevices = TDEGlobal::hardwareDevices();
+ TDEGenericHardwareList cardReaderList = hwdevices->listByDeviceClass(TDEGenericDeviceType::CryptographicCard);
+ for (hwdevice = cardReaderList.first(); hwdevice; hwdevice = cardReaderList.next())
+ {
+ TDECryptographicCardDevice *cdevice = static_cast<TDECryptographicCardDevice*>(hwdevice);
+ connect(cdevice, TQ_SIGNAL(certificateListAvailable(TDECryptographicCardDevice*)),
+ this, TQ_SLOT(cryptographicCardInserted(TDECryptographicCardDevice*)));
+ connect(cdevice, TQ_SIGNAL(cardRemoved(TDECryptographicCardDevice*)),
+ this, TQ_SLOT(cryptographicCardRemoved(TDECryptographicCardDevice*)));
+ cdevice->enableCardMonitoring(true);
+ }
+
+ // Check card login status
+ KUser userinfo;
+ TQString fileName = userinfo.homeDir() + "/.tde_card_login_state";
+ TQFile flagFile(fileName);
+ if (flagFile.open(IO_ReadOnly))
+ {
+ TQTextStream stream(&flagFile);
+ if (stream.readLine().startsWith("1"))
+ {
+ // Card was likely used to log in
+ TQTimer::singleShot(5000, this, TQ_SLOT(cardStartupTimeout()));
+ }
+ flagFile.close();
+ }
+#endif
+
+ dBusConnect();
+}
+
+SaverEngine::~SaverEngine()
+{
+ m_saverEngineEventHandler->terminateLockProcess();
+ delete mXAutoLock;
+ dBusClose();
+
+ // Restore X screensaver parameters
+ XSetScreenSaver(tqt_xdisplay(), mXTimeout, mXInterval, mXBlanking, mXExposures);
+ emit terminateEventHandlerThread();
+ m_eventHandlerThread->wait();
+ delete m_saverEngineEventHandler;
+ delete m_eventHandlerThread;
+}
+
+void SaverEngine::cardStartupTimeout()
+{
+ if (!mValidCryptoCardInserted)
+ {
+ configure(); // Restore saver timeout
+ lockScreen(); // Force lock
+ }
+}
+
+void SaverEngine::cryptographicCardInserted(TDECryptographicCardDevice* cdevice)
+{
+#ifdef WITH_TDEHWLIB
+ TQString login_name = TQString::null;
+ X509CertificatePtrList certList = cdevice->cardX509Certificates();
+ if (certList.count() > 0)
+ {
+ KSSLCertificate* card_cert = NULL;
+ card_cert = KSSLCertificate::fromX509(certList[0]);
+ TQStringList cert_subject_parts = TQStringList::split("/", card_cert->getSubject(), false);
+ for (TQStringList::Iterator it = cert_subject_parts.begin(); it != cert_subject_parts.end(); ++it)
+ {
+ TQString lcpart = (*it).lower();
+ if (lcpart.startsWith("cn="))
+ {
+ login_name = lcpart.right(lcpart.length() - strlen("cn="));
+ }
+ }
+ delete card_cert;
+ }
+
+ if (login_name != "")
+ {
+ KUser user;
+ if (login_name == user.loginName())
+ {
+ mValidCryptoCardInserted = true;
+ }
+ }
+#endif
+}
+
+void SaverEngine::cryptographicCardRemoved(TDECryptographicCardDevice* cdevice)
+{
+#ifdef WITH_TDEHWLIB
+ if (mValidCryptoCardInserted)
+ {
+ mValidCryptoCardInserted = false;
+
+ // Restore saver timeout
+ configure();
+
+ // Force lock
+ lockScreen();
+ }
+#endif
+}
+
+// DCOP interface method
+void SaverEngine::lock()
+{
+ lockScreen(true);
+}
+
+void SaverEngine::lockScreen(bool dcop)
+{
+ if (mValidCryptoCardInserted)
+ {
+ kdDebug(1204) << "SaverEngine: crypto card inserted, ignore lock request" << endl;
+ return;
+ }
+ emit lockScreenSignal(dcop);
+}
+
+void SaverEngine::lockScreenGUI()
+{
+ DCOPClientTransaction *trans = tdeApp->dcopClient()->beginTransaction();
+ if (trans)
+ {
+ mLockTransactions.append(trans);
+ }
+}
+
+void SaverEngine::processLockTransactions()
+{
+ TQValueVector<DCOPClientTransaction*>::ConstIterator it = mLockTransactions.begin();
+ for (; it != mLockTransactions.end(); ++it)
+ {
+ TQCString replyType = "void";
+ TQByteArray arr;
+ tdeApp->dcopClient()->endTransaction(*it, replyType, arr);
+ }
+ mLockTransactions.clear();
+}
+
+void SaverEngine::saverLockReady()
+{
+ if (m_saverEngineEventHandler->getState() != SaverState::Engaging)
+ {
+ kdDebug(1204) << "Got unexpected saverLockReady()" << endl;
+ }
+
+ kdDebug(1204) << "Saver Lock Ready" << endl;
+ processLockTransactions();
+}
+
+// DCOP interface method
+void SaverEngine::save()
+{
+ if (mValidCryptoCardInserted)
+ {
+ kdDebug(1204) << "SaverEngine: crypto card inserted, ignore save request" << endl;
+ return;
+ }
+ TQTimer::singleShot(0, m_saverEngineEventHandler, TQ_SLOT(saveScreen()));
+}
+
+// DCOP interface method
+void SaverEngine::quit()
+{
+ TQTimer::singleShot(0, m_saverEngineEventHandler, TQ_SLOT(stopLockProcess()));
+}
+
+// DCOP interface method
+bool SaverEngine::isEnabled()
+{
+ return mEnabled;
+}
+
+// DCOP interface method
+bool SaverEngine::enable(bool e)
+{
+ if (e == mEnabled)
+ return true;
+
+ // If we aren't in a suitable state, we will not reconfigure.
+ if (m_saverEngineEventHandler->getState() != SaverState::Waiting)
+ return false;
+
+ mEnabled = e;
+
+ if (mEnabled)
+ {
+ if (!mXAutoLock)
+ {
+ mXAutoLock = new XAutoLock();
+ connect(mXAutoLock, TQ_SIGNAL(timeout()), TQ_SLOT(idleTimeout()));
+ }
+ mXAutoLock->setTimeout(mTimeout);
+ mXAutoLock->setDPMS(true);
+
+ // We'll handle blanking
+ XSetScreenSaver(tqt_xdisplay(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures);
+ mXAutoLock->start();
+ kdDebug(1204) << "Saver engine started, timeout: " << mTimeout << endl;
+ }
+ else
+ {
+ if (mXAutoLock)
+ {
+ delete mXAutoLock;
+ mXAutoLock = nullptr;
+ }
+
+ XForceScreenSaver(tqt_xdisplay(), ScreenSaverReset);
+ XSetScreenSaver(tqt_xdisplay(), 0, mXInterval, PreferBlanking, DontAllowExposures);
+ kdDebug(1204) << "Saver engine disabled" << endl;
+ }
+
+ return true;
+}
+
+// DCOP interface method
+bool SaverEngine::isBlanked()
+{
+ return (m_saverEngineEventHandler->getState() != SaverState::Waiting);
+}
+
+void SaverEngine::enableExports()
+{
+#ifdef TQ_WS_X11
+ kdDebug(270) << k_lineinfo << "activating background exports" << endl;
+ DCOPClient *client = tdeApp->dcopClient();
+ if (!client->isAttached())
+ {
+ client->attach();
+ }
+ TQByteArray data;
+ TQDataStream args(data, IO_WriteOnly);
+ args << 1;
+
+ TQCString appname("kdesktop");
+ int screen_number = DefaultScreen(tqt_xdisplay());
+ if (screen_number)
+ {
+ appname.sprintf("kdesktop-screen-%d", screen_number);
+ }
+
+ client->send(appname, "KBackgroundIface", "setExport(int)", data);
+#endif
+}
+
+// Read and apply configuration.
+void SaverEngine::configure()
+{
+ // If we aren't in a suitable state, we will not reconfigure.
+ if (m_saverEngineEventHandler->getState() != SaverState::Waiting)
+ {
+ return;
+ }
+
+ // create a new config obj to ensure we read the latest options
+ KDesktopSettings::self()->readConfig();
+
+ mTimeout = KDesktopSettings::timeout();
+ bool e = KDesktopSettings::screenSaverEnabled();
+ mEnabled = !e; // enable the screensaver by forcibly toggling it
+ enable(e);
+
+ int action;
+ action = KDesktopSettings::actionTopLeft();
+ xautolock_corners[0] = applyManualSettings(action);
+ action = KDesktopSettings::actionTopRight();
+ xautolock_corners[1] = applyManualSettings(action);
+ action = KDesktopSettings::actionBottomLeft();
+ xautolock_corners[2] = applyManualSettings(action);
+ action = KDesktopSettings::actionBottomRight();
+ xautolock_corners[3] = applyManualSettings(action);
+}
+
+// DCOP interface method
+// Set a variable to indicate only to blank the screen and not use the saver
+void SaverEngine::setBlankOnly(bool blankOnly)
+{
+ mBlankOnly = blankOnly;
+}
+
+void SaverEngine::activateSaverOrLockGUI()
+{
+ XSetScreenSaver(tqt_xdisplay(), 0, mXInterval, PreferBlanking, mXExposures);
+ if (mXAutoLock)
+ {
+ mXAutoLock->stop();
+ }
+ emitDCOPSignal("KDE_start_screensaver()", TQByteArray());
+}
+
+void SaverEngine::stopLockProcessGUI()
+{
+ emitDCOPSignal("KDE_stop_screensaver()", TQByteArray());
+
+ if (mEnabled)
+ {
+ if (mXAutoLock)
+ {
+ mXAutoLock->start();
+ }
+ XForceScreenSaver(tqt_xdisplay(), ScreenSaverReset);
+ XSetScreenSaver(tqt_xdisplay(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures);
+ }
+ processLockTransactions();
+
+ if (systemdSession && systemdSession->canSend())
+ {
+ TQValueList<TQT_DBusData> params;
+ params << TQT_DBusData::fromBool(false);
+ TQT_DBusMessage reply = systemdSession->sendWithReply("SetIdleHint", params);
+ }
+}
+
+void SaverEngine::terminateTDESession()
+{
+ // Terminate the TDE session ASAP!
+ // Values are explained at http://lists.kde.org/?l=kde-linux&m=115770988603387
+ TQByteArray data;
+ TQDataStream arg(data, IO_WriteOnly);
+ arg << (int)0 << (int)0 << (int)2;
+ if (!tdeApp->dcopClient()->send("ksmserver", "default", "logout(int,int,int)", data))
+ {
+ // Someone got to DCOP before we did. Try an emergency system logout
+ system("logout");
+ }
+}
+
+void SaverEngine::lockProcessFullyActivatedGUI()
+{
+ if (systemdSession && systemdSession->canSend())
+ {
+ TQValueList<TQT_DBusData> params;
+ params << TQT_DBusData::fromBool(true);
+ TQT_DBusMessage reply = systemdSession->sendWithReply("SetIdleHint", params);
+ }
+
+ if (mNewVTAfterLockEngage)
+ {
+ DM().startReserve();
+ mNewVTAfterLockEngage = false;
+ }
+ else if (mSwitchVTAfterLockEngage != -1)
+ {
+ DM().switchVT(mSwitchVTAfterLockEngage);
+ mSwitchVTAfterLockEngage = -1;
+ }
+}
+
+// XAutoLock has detected the required idle time.
+void SaverEngine::idleTimeout()
+{
+ if (!mValidCryptoCardInserted)
+ {
+ // disable X screensaver
+ XForceScreenSaver(tqt_xdisplay(), ScreenSaverReset);
+ XSetScreenSaver(tqt_xdisplay(), 0, mXInterval, PreferBlanking, DontAllowExposures);
+ emit activateSaverOrLockSignal(DefaultLock);
+ }
+}
+
+xautolock_corner_t SaverEngine::applyManualSettings(int action)
+{
+ if (action == 0)
+ {
+ kdDebug() << "no lock" << endl;
+ return ca_nothing;
+ }
+ else if (action == 1)
+ {
+ kdDebug() << "lock screen" << endl;
+ return ca_forceLock;
+ }
+ else if (action == 2)
+ {
+ kdDebug() << "prevent lock" << endl;
+ return ca_dontLock;
+ }
+ else
+ {
+ kdDebug() << "no lock nothing" << endl;
+ return ca_nothing;
+ }
+}
+
+/*
+ * This function try to reconnect to D-Bus.
+ * \return boolean with the result of the operation
+ * \retval true if successful reconnected to D-Bus
+ * \retval false if unsuccessful
+ */
+bool SaverEngine::dBusReconnect()
+{
+ dBusClose(); // close D-Bus connection
+ return (dBusConnect()); // init D-Bus conntection
+}
+
+// This function is used to close D-Bus connection.
+void SaverEngine::dBusClose()
+{
+ if (dBusConn.isConnected())
+ {
+ if (dBusLocal)
+ {
+ delete dBusLocal;
+ dBusLocal = nullptr;
+ }
+ if (dBusWatch)
+ {
+ delete dBusWatch;
+ dBusWatch = nullptr;
+ }
+ if (systemdSession)
+ {
+ delete systemdSession;
+ systemdSession = nullptr;
+ }
+ }
+ dBusConn.closeConnection(DBUS_CONN_NAME);
+}
+
+// This function is used to connect to D-Bus.
+bool SaverEngine::dBusConnect()
+{
+ dBusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus, DBUS_CONN_NAME);
+ if (!dBusConn.isConnected())
+ {
+ kdError() << "Failed to open connection to system message bus: " << dBusConn.lastError().message() << endl;
+ TQTimer::singleShot(4000, this, TQ_SLOT(dBusReconnect()));
+ return false;
+ }
+
+ // watcher for Disconnect signal
+ dBusLocal = new TQT_DBusProxy(DBUS_SERVICE_DBUS, DBUS_PATH_LOCAL, DBUS_INTERFACE_LOCAL, dBusConn);
+ TQObject::connect(dBusLocal, TQ_SIGNAL(dbusSignal(const TQT_DBusMessage&)),
+ this, TQ_SLOT(handleDBusSignal(const TQT_DBusMessage&)));
+
+ // watcher for NameOwnerChanged signals
+ dBusWatch = new TQT_DBusProxy(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, dBusConn);
+ TQObject::connect(dBusWatch, TQ_SIGNAL(dbusSignal(const TQT_DBusMessage&)),
+ this, TQ_SLOT(handleDBusSignal(const TQT_DBusMessage&)));
+
+ // find already running SystemD
+ TQT_DBusProxy checkSystemD(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, dBusConn);
+ if (checkSystemD.canSend())
+ {
+ TQValueList<TQT_DBusData> params;
+ params << TQT_DBusData::fromString(SYSTEMD_LOGIN1_SERVICE);
+ TQT_DBusMessage reply = checkSystemD.sendWithReply("NameHasOwner", params);
+ if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 && reply[0].toBool())
+ {
+ onDBusServiceRegistered(SYSTEMD_LOGIN1_SERVICE);
+ }
+ }
+ return true;
+}
+
+// This function handles D-Bus service registering
+void SaverEngine::onDBusServiceRegistered(const TQString& service)
+{
+ if (service == SYSTEMD_LOGIN1_SERVICE)
+ {
+ // get current systemd session
+ TQT_DBusProxy managerIface(SYSTEMD_LOGIN1_SERVICE, SYSTEMD_LOGIN1_PATH, SYSTEMD_LOGIN1_MANAGER_IFACE, dBusConn);
+ TQT_DBusObjectPath systemdSessionPath = TQT_DBusObjectPath();
+ if (managerIface.canSend())
+ {
+ TQValueList<TQT_DBusData> params;
+ params << TQT_DBusData::fromUInt32(getpid());
+ TQT_DBusMessage reply = managerIface.sendWithReply("GetSessionByPID", params);
+ if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1)
+ {
+ systemdSessionPath = reply[0].toObjectPath();
+ }
+ }
+ // wather for systemd session signals
+ if (systemdSessionPath.isValid())
+ {
+ systemdSession = new TQT_DBusProxy(SYSTEMD_LOGIN1_SERVICE, systemdSessionPath, SYSTEMD_LOGIN1_SESSION_IFACE, dBusConn);
+ TQObject::connect(systemdSession, TQ_SIGNAL(dbusSignal(const TQT_DBusMessage&)),
+ this, TQ_SLOT(handleDBusSignal(const TQT_DBusMessage&)));
+ }
+ return;
+ }
+}
+
+// This function handles D-Bus service unregistering
+void SaverEngine::onDBusServiceUnregistered(const TQString& service)
+{
+ if (service == SYSTEMD_LOGIN1_SERVICE)
+ {
+ if (systemdSession)
+ {
+ delete systemdSession;
+ systemdSession = nullptr;
+ }
+ return;
+ }
+}
+
+// This function handles signals from the D-Bus daemon.
+void SaverEngine::handleDBusSignal(const TQT_DBusMessage& msg)
+{
+ // dbus terminated
+ if (msg.path() == DBUS_PATH_LOCAL && msg.interface() == DBUS_INTERFACE_LOCAL &&
+ msg.member() == "Disconnected")
+ {
+ dBusClose();
+ TQTimer::singleShot(1000, this, TQ_SLOT(dBusReconnect()));
+ return;
+ }
+
+ // service registered / unregistered
+ if (msg.path() == DBUS_PATH_DBUS && msg.interface() == DBUS_INTERFACE_DBUS &&
+ msg.member() == "NameOwnerChanged")
+ {
+ if (msg[1].toString().isEmpty())
+ {
+ // old-owner is empty
+ onDBusServiceRegistered(msg[0].toString());
+ }
+ if (msg[2].toString().isEmpty())
+ {
+ // new-owner is empty
+ onDBusServiceUnregistered(msg[0].toString());
+ }
+ return;
+ }
+
+ // systemd signal Lock()
+ if (systemdSession && systemdSession->canSend() && msg.path() == systemdSession->path() &&
+ msg.interface() == SYSTEMD_LOGIN1_SESSION_IFACE && msg.member() == "Lock")
+ {
+ lockScreen();
+ return;
+ }
+
+ // systemd signal Unlock()
+ if (systemdSession && systemdSession->canSend() && msg.path() == systemdSession->path() &&
+ msg.interface() == SYSTEMD_LOGIN1_SESSION_IFACE && msg.member() == "Unlock")
+ {
+ // unlock?
+ return;
+ }
+}
+
+void SaverEngine::lockScreenAndDoNewSession()
+{
+ mNewVTAfterLockEngage = true;
+ lockScreen();
+}
+
+void SaverEngine::lockScreenAndSwitchSession(int vt)
+{
+ mSwitchVTAfterLockEngage = vt;
+ lockScreen();
+}
+
+SaverEngineEventHandler::SaverEngineEventHandler(SaverEngine *engine) :
+ m_state(Waiting), m_saverProcessReady(false), m_lockProcessRestarting(false),
+ m_terminationRequest(false), m_saverEngine(engine), m_SAKProcess(nullptr)
+{
+ connect(&m_lockProcess, TQ_SIGNAL(processExited(TDEProcess*)),
+ this, TQ_SLOT(slotLockProcessExited()));
+}
+
+void SaverEngineEventHandler::terminateLockProcess()
+{
+ if (m_state == Waiting)
+ {
+ kill(m_lockProcess.pid(), SIGKILL);
+ }
+ m_lockProcess.detach(); // don't kill it if we crash
+}
+
+void SaverEngineEventHandler::lockCompleted()
+{
+ kdDebug(1204) << "SaverEngineEventHandler: lock completed" << endl;
+
+ if (m_state == Waiting)
+ {
+ return;
+ }
+
+ m_state = Waiting;
+ if (trinity_lockeng_sak_available)
+ {
+ startSAKProcess();
+ }
+ TQTimer::singleShot(0, m_saverEngine, TQ_SLOT(stopLockProcessGUI()));
+}
+
+void SaverEngineEventHandler::lockFullyActivated()
+{
+ m_state = Saving;
+ TQTimer::singleShot(0, m_saverEngine, TQ_SLOT(lockProcessFullyActivatedGUI()));
+}
+
+void SaverEngineEventHandler::lockReady()
+{
+ m_saverProcessReady = true;
+}
+
+void SaverEngineEventHandler::lockScreen(bool dcop)
+{
+ if (m_lockProcessRestarting)
+ {
+ kdDebug(1204) << "SaverEngineEventHandler: lock process is restarting, can't handle lock request" << endl;
+ return;
+ }
+
+ bool ok = true;
+ if (m_state == Waiting)
+ {
+ ok = activateSaverOrLock(ForceLock);
+ // It takes a while for kdesktop_lock to start and lock the screen.
+ // Therefore delay the DCOP call until it tells kdesktop that the locking is in effect.
+ // This is done only for --forcelock .
+ if (ok && m_state != Saving)
+ {
+ if (dcop)
+ {
+ TQTimer::singleShot(0, m_saverEngine, TQ_SLOT(lockScreenGUI()));
+ }
+ }
+ }
+}
+
+void SaverEngineEventHandler::saveScreen()
+{
+ if (m_lockProcessRestarting)
+ {
+ kdDebug(1204) << "SaverEngineEventHandler: lock process is restarting, can't handle save request" << endl;
+ return;
+ }
+
+ if (m_state == Waiting)
+ {
+ activateSaverOrLock(DefaultLock);
+ }
+}
+
+void SaverEngineEventHandler::slotLockProcessExited()
+{
+ // Clean up status after the lock process has exited
+ lockCompleted();
+
+ m_lockProcessRestarting = true;
+
+ bool abnormalExit = false;
+ if (!m_lockProcess.normalExit())
+ {
+ abnormalExit = true;
+ }
+ else if (m_lockProcess.exitStatus() != 0)
+ {
+ abnormalExit = true;
+ }
+ if (m_terminationRequest)
+ {
+ abnormalExit = false;
+ m_terminationRequest = false;
+ }
+
+ // Restart the lock process. This call blocks till
+ // the lock process has restarted.
+ restartLockProcess();
+
+ if (abnormalExit)
+ {
+ // Possible hacking attempt detected, try to relaunch the saver with force lock
+ m_state = Waiting;
+ if (!activateSaverOrLock(ForceLock))
+ {
+ TQTimer::singleShot(0, m_saverEngine, TQ_SLOT(terminateTDESession()));
+ }
+ }
+ m_lockProcessRestarting = false;
+}
+
+/*
+ * Start or restart the lock process.
+ * On the very first invocation, launch the SAK process if required and
+ * auto lock the screen if the option has been enabled in the configuration.
+ */
+bool SaverEngineEventHandler::restartLockProcess()
+{
+ static bool firstStart = true;
+
+ bool autoLoginEnable = false;
+ bool autoLoginLocked = false;
+ if (firstStart)
+ {
+ firstStart = false;
+
+ // Create SAK process only if SAK is enabled
+ struct stat st;
+ TDESimpleConfig *config;
+ if (stat(KDE_CONFDIR "/tdm/tdmdistrc" , &st) == 0)
+ {
+ config = new TDESimpleConfig(TQString::fromLatin1(KDE_CONFDIR "/tdm/tdmdistrc"));
+ }
+ else
+ {
+ config = new TDESimpleConfig(TQString::fromLatin1(KDE_CONFDIR "/tdm/tdmrc"));
+ }
+ config->setGroup("X-:*-Greeter");
+ bool useSAKProcess = false;
+#ifdef BUILD_TSAK
+ useSAKProcess = config->readBoolEntry("UseSAK", false) && KDesktopSettings::useTDESAK();
+#endif
+ if (useSAKProcess)
+ {
+ startSAKProcess();
+ }
+
+ // autolock the desktop if required
+ config->setGroup("X-:0-Core");
+ autoLoginEnable = config->readBoolEntry("AutoLoginEnable", false);
+ autoLoginLocked = config->readBoolEntry("AutoLoginLocked", false);
+ delete config;
+ }
+
+ // (Re)start the lock process
+ if (!m_lockProcess.isRunning())
+ {
+ m_lockProcess.clearArguments();
+ TQString path = TDEStandardDirs::findExe("kdesktop_lock");
+ if (path.isEmpty())
+ {
+ kdDebug(1204) << "Can't find kdesktop_lock!" << endl;
+ return false;
+ }
+ m_lockProcess << path;
+ m_lockProcess << TQString("--internal") << TQString("%1").arg(getpid());
+
+ m_saverProcessReady = false;
+ if (!m_lockProcess.start())
+ {
+ kdDebug(1204) << "Failed to start kdesktop_lock!" << endl;
+ return false;
+ }
+ // Wait for the lock process to signal that it is ready
+ sigset_t empty_mask;
+ sigemptyset(&empty_mask);
+ while (!m_saverProcessReady)
+ {
+ sigsuspend(&empty_mask);
+ }
+ if (!m_lockProcess.isRunning())
+ {
+ kdDebug(1204) << "Failed to initialize kdesktop_lock (unexpected termination)!" << endl;
+ return false;
+ }
+ }
+
+ if (autoLoginEnable && autoLoginLocked)
+ {
+ m_lockProcess.kill(SIGTTOU);
+ m_lockProcess.kill(SIGUSR1);
+ }
+ return true;
+}
+
+// Start the screen saver or lock screen
+bool SaverEngineEventHandler::activateSaverOrLock(LockType lock_type)
+{
+ if (m_state == Saving)
+ {
+ return true;
+ }
+
+ kdDebug(1204) << "SaverEngineEventHandler: starting saver" << endl;
+ m_state = Preparing;
+ if (m_SAKProcess)
+ {
+ m_SAKProcess->kill(SIGTERM);
+ }
+
+ m_saverEngine->enableExports();
+ if (!restartLockProcess())
+ {
+ m_state = Waiting;
+ return false;
+ }
+
+ switch (lock_type)
+ {
+ case ForceLock:
+ m_lockProcess.kill(SIGUSR1); // Request forcelock
+ break;
+ case DontLock:
+ m_lockProcess.kill(SIGUSR2); // Request dontlock
+ break;
+ case SecureDialog:
+ m_lockProcess.kill(SIGWINCH); // Request secure dialog
+ break;
+ default:
+ break;
+ }
+
+ if (m_saverEngine->mBlankOnly)
+ {
+ m_lockProcess.kill(SIGTTIN); // Request blanking
+ }
+
+ int ret = m_lockProcess.kill(SIGTTOU); // Start lock
+ if (!ret)
+ {
+ m_state = Waiting;
+ return false;
+ }
+ m_state = Engaging;
+
+ // Ask to the GUI thread to activate X11 saver
+ TQTimer::singleShot(0, m_saverEngine, TQ_SLOT(activateSaverOrLockGUI()));
+
+ return true;
+}
+
+// Stop the screen saver.
+void SaverEngineEventHandler::stopLockProcess()
+{
+ if (m_state == Waiting)
+ {
+ return;
+ }
+
+ kdDebug(1204) << "SaverEngineEventHandler: stopping lock process" << endl;
+
+ m_terminationRequest = true;
+ m_lockProcess.kill();
+ m_state = Waiting;
+
+ // Ask to the GUI thread to stop the X11 saver
+ TQTimer::singleShot(0, m_saverEngine, TQ_SLOT(stopLockProcessGUI()));
+}
+
+void SaverEngineEventHandler::startSAKProcess()
+{
+ if (!m_SAKProcess)
+ {
+ m_SAKProcess = new TDEProcess;
+ *m_SAKProcess << "tdmtsak";
+ connect(m_SAKProcess, TQ_SIGNAL(processExited(TDEProcess*)), this, TQ_SLOT(slotSAKProcessExited()));
+ }
+ if (!m_SAKProcess->isRunning())
+ {
+ m_SAKProcess->start();
+ }
+}
+
+void SaverEngineEventHandler::slotSAKProcessExited()
+{
+ if (!m_SAKProcess)
+ {
+ tqWarning("[kdesktop] SAK process does not exist. Something went wrong. Ignoring.");
+ return;
+ }
+
+ int retcode = m_SAKProcess->exitStatus();
+ if (retcode && m_SAKProcess->normalExit())
+ {
+ trinity_lockeng_sak_available = false;
+ tqWarning("[kdesktop] SAK driven secure dialog is not available for use (retcode %d). "
+ "Check tdmtsak for proper functionality.", retcode);
+ }
+
+ if (m_state == Preparing)
+ {
+ return;
+ }
+
+ if (m_SAKProcess->normalExit() && trinity_lockeng_sak_available)
+ {
+ if (m_state == Waiting)
+ {
+ activateSaverOrLock(SecureDialog);
+ }
+ else
+ {
+ m_lockProcess.kill(SIGHUP);
+ }
+ }
+}
+
+void SaverEngineEventHandler::terminateThread()
+{
+ TQEventLoop *eventLoop = TQApplication::eventLoop();
+ if (eventLoop)
+ {
+ eventLoop->exit(0);
+ }
+}