From ce477303019c7f3ba18dcab48e4205d59614ce5a Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Thu, 17 Sep 2015 17:30:17 -0500 Subject: [PATCH] Add initial cryptographic card login support Tested with themed greeter and SAK disabled --- kcheckpass/checkpass_pam.c | 16 +- kcontrol/hwmanager/devicepropsdlg.cpp | 16 +- kdesktop/lock/lockdlg.cc | 22 +- kdesktop/lock/lockdlg.h | 3 + kdesktop/lock/lockprocess.cc | 154 ++++++++++++-- kdesktop/lock/lockprocess.h | 10 + kdesktop/lock/main.cc | 12 +- kdesktop/lockeng.cc | 82 +++++-- kdesktop/lockeng.h | 5 + tdm/CMakeLists.txt | 1 + tdm/backend/client.c | 19 +- tdm/cryptocardwatcher/CMakeLists.txt | 32 +++ tdm/cryptocardwatcher/main.cpp | 139 ++++++++++++ tdm/cryptocardwatcher/watcher.cc | 86 ++++++++ tdm/cryptocardwatcher/watcher.h | 40 ++++ tdm/kfrontend/CMakeLists.txt | 2 +- tdm/kfrontend/kgapp.cpp | 12 ++ tdm/kfrontend/kgreeter.cpp | 72 +++++++ tdm/kfrontend/kgreeter.h | 4 + tdm/kfrontend/kgverify.cpp | 200 ++++++++++++------ tdm/kfrontend/kgverify.h | 4 + tdm/kfrontend/themer/tdmitem.cpp | 21 +- tdm/kfrontend/themer/tdmitem.h | 1 + tdm/kfrontend/themer/tdmlabel.h | 6 +- tdm/kfrontend/themer/tdmthemer.cpp | 6 + tdm/kfrontend/themer/tdmthemer.h | 1 + tdm/kfrontend/themes/circles/circles.xml | 4 +- .../themes/minimalist/minimalist.xml | 4 +- .../themes/o2_enterprise/enterprise.xml | 4 +- tdmlib/dmctl.cpp | 88 ++++++-- tdmlib/kgreet_classic.cpp | 69 +++++- tdmlib/kgreet_classic.h | 3 + tdmlib/kgreet_pam.cpp | 4 + tdmlib/kgreet_pam.h | 1 + tdmlib/kgreet_winbind.cpp | 4 + tdmlib/kgreet_winbind.h | 1 + tdmlib/kgreeterplugin.h | 8 +- 37 files changed, 1006 insertions(+), 150 deletions(-) create mode 100644 tdm/cryptocardwatcher/CMakeLists.txt create mode 100644 tdm/cryptocardwatcher/main.cpp create mode 100644 tdm/cryptocardwatcher/watcher.cc create mode 100644 tdm/cryptocardwatcher/watcher.h diff --git a/kcheckpass/checkpass_pam.c b/kcheckpass/checkpass_pam.c index 7a35eeddf..b11148cee 100644 --- a/kcheckpass/checkpass_pam.c +++ b/kcheckpass/checkpass_pam.c @@ -72,8 +72,20 @@ PAM_conv (int num_msg, pam_message_type **msg, repl[count].resp = pd->conv(ConvGetNormal, msg[count]->msg); break; case PAM_PROMPT_ECHO_OFF: - repl[count].resp = - pd->conv(ConvGetHidden, pd->classic ? 0 : msg[count]->msg); + if (pd->classic) { + // WARNING + // This is far from foolproof, but it's the best we can do at this time... + // Try to detect PIN entry requests + if (strstr(msg[count]->msg, "PIN")) { + repl[count].resp = pd->conv(ConvGetHidden, msg[count]->msg); + } + else { + repl[count].resp = pd->conv(ConvGetHidden, 0); + } + } + else { + repl[count].resp = pd->conv(ConvGetHidden, msg[count]->msg); + } break; #ifdef PAM_BINARY_PROMPT case PAM_BINARY_PROMPT: diff --git a/kcontrol/hwmanager/devicepropsdlg.cpp b/kcontrol/hwmanager/devicepropsdlg.cpp index a1ef81c2b..9946ede6e 100644 --- a/kcontrol/hwmanager/devicepropsdlg.cpp +++ b/kcontrol/hwmanager/devicepropsdlg.cpp @@ -779,8 +779,8 @@ void DevicePropertiesDialog::populateDeviceInformation() { if (m_device->type() == TDEGenericDeviceType::CryptographicCard) { TDECryptographicCardDevice* cdevice = static_cast(m_device); - connect(cdevice, TQT_SIGNAL(cardInserted()), this, TQT_SLOT(cryptographicCardInserted())); - connect(cdevice, TQT_SIGNAL(cardRemoved()), this, TQT_SLOT(cryptographicCardRemoved())); + connect(cdevice, TQT_SIGNAL(cardInserted(TDECryptographicCardDevice*)), this, TQT_SLOT(cryptographicCardInserted())); + connect(cdevice, TQT_SIGNAL(cardRemoved(TDECryptographicCardDevice*)), this, TQT_SLOT(cryptographicCardRemoved())); updateCryptographicCardStatusDisplay(); } @@ -926,6 +926,7 @@ void DevicePropertiesDialog::cryptLUKSAddKey() { unsigned int key_slot = lvi->text(0).toUInt(); bool allow_card = false; bool use_card = false; + bool luks_card_key_modified = false; KSSLCertificate* card_cert = NULL; X509* card_cert_x509; TQString disk_uuid = sdevice->diskUUID(); @@ -988,6 +989,7 @@ void DevicePropertiesDialog::cryptLUKSAddKey() { // Use the secret key as the LUKS passcode new_password = randomKey; + luks_card_key_modified = true; } else { KMessageBox::error(this, i18n("Key creation failed
Please check that you have write access to /etc/trinity/luks/card and try again
"), i18n("Key creation failure")); @@ -1081,6 +1083,16 @@ void DevicePropertiesDialog::cryptLUKSAddKey() { sdevice->cryptClearOperationsUnlockPassword(); KMessageBox::error(this, i18n("Key write failed
Please check the LUKS password and try again
"), i18n("Key write failure")); } + else { + if (luks_card_key_modified) { + if (KMessageBox::warningYesNo(this, i18n("You have created a new card-dependent key
Card-dependent keys work in conjunction with an encrypted key file stored on the host system.
When a card is used to boot, card-dependent keys must be updated in the initramfs image to become usable.

Would you like to update the initramfs image now?"), i18n("Update Required")) == KMessageBox::Yes) { + // Update the initramfs + if (system("update-initramfs -u -k all") != 0) { + KMessageBox::error(this, i18n("Initramfs update failed
Card-dependent keys may not be available for use until the root storage device is available / unlocked
"), i18n("Initramfs update failure")); + } + } + } + } } } } diff --git a/kdesktop/lock/lockdlg.cc b/kdesktop/lock/lockdlg.cc index e75ac2b18..827495c33 100644 --- a/kdesktop/lock/lockdlg.cc +++ b/kdesktop/lock/lockdlg.cc @@ -513,7 +513,17 @@ void PasswordDlg::handleVerify() case ConvGetHidden: if (!GRecvArr( &arr )) break; - greet->textPrompt( arr, false, false ); + if (arr && (arr[0] != 0)) { + // Reset password entry and change text + greet->start(); + greet->textPrompt( arr, false, false ); + // Force relayout + setFixedSize( sizeHint().width(), sizeHint().height() + 1 ); + setFixedSize( sizeHint() ); + } + else { + greet->textPrompt( arr, false, false ); + } if (arr) ::free( arr ); return; @@ -915,4 +925,14 @@ void PasswordDlg::capsLocked() updateLabel(); } +void PasswordDlg::attemptCardLogin() { + greet->start(); + greet->next(); +} + +void PasswordDlg::resetCardLogin() { + greet->abort(); + greet->start(); +} + #include "lockdlg.moc" diff --git a/kdesktop/lock/lockdlg.h b/kdesktop/lock/lockdlg.h index eea0931ab..1bcb75671 100644 --- a/kdesktop/lock/lockdlg.h +++ b/kdesktop/lock/lockdlg.h @@ -49,6 +49,9 @@ class PasswordDlg : public TQDialog, public KGreeterPluginHandler virtual void gplugStart(); virtual void gplugActivity(); virtual void gplugMsgBox( TQMessageBox::Icon type, const TQString &text ); + + virtual void attemptCardLogin(); + virtual void resetCardLogin(); protected: virtual void timerEvent(TQTimerEvent *); diff --git a/kdesktop/lock/lockprocess.cc b/kdesktop/lock/lockprocess.cc index aa9514312..494852e39 100644 --- a/kdesktop/lock/lockprocess.cc +++ b/kdesktop/lock/lockprocess.cc @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,8 @@ Status DPMSInfo ( Display *, CARD16 *, BOOL * ); #include #endif +#define KDESKTOP_DEBUG_ID 1204 + #define LOCK_GRACE_DEFAULT 5000 #define AUTOLOGOUT_DEFAULT 600 @@ -146,7 +149,7 @@ Atom kde_wm_transparent_to_black = 0; static void segv_handler(int) { - kdError(1204) << "A fatal exception was encountered." + kdError(KDESKTOP_DEBUG_ID) << "A fatal exception was encountered." << " Trapping and ignoring it so as not to compromise desktop security..." << kdBacktrace() << endl; sleep(1); @@ -272,7 +275,7 @@ LockProcess::LockProcess() KServiceGroup::Ptr servGroup = KServiceGroup::baseGroup( "screensavers"); if (servGroup) { relPath=servGroup->relPath(); - kdDebug(1204) << "relPath=" << relPath << endl; + kdDebug(KDESKTOP_DEBUG_ID) << "relPath=" << relPath << endl; } TDEGlobal::dirs()->addResourceType("scrsav", TDEGlobal::dirs()->kde_default("apps") + @@ -290,6 +293,19 @@ LockProcess::LockProcess() } } + // 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(hwdevice); + // connect(cdevice, SIGNAL(pinRequested(TQString,TDECryptographicCardDevice*)), this, SLOT(cryptographicCardPinRequested(TQString,TDECryptographicCardDevice*))); + connect(cdevice, TQT_SIGNAL(cardInserted(TDECryptographicCardDevice*)), this, TQT_SLOT(cryptographicCardInserted(TDECryptographicCardDevice*))); + connect(cdevice, TQT_SIGNAL(cardRemoved(TDECryptographicCardDevice*)), this, TQT_SLOT(cryptographicCardRemoved(TDECryptographicCardDevice*))); + cdevice->enableCardMonitoring(true); + // cdevice->enablePINEntryCallbacks(true); + } + #ifdef KEEP_MOUSE_UNGRABBED setEnabled(false); #endif @@ -781,11 +797,11 @@ void LockProcess::readSaver() TQStringList saverTypes = TQStringList::split(";", saverType); for (uint i = 0; i < saverTypes.count(); i++) { if ((saverTypes[i] == "ManipulateScreen") && !manipulatescreen) { - kdDebug(1204) << "Screensaver is type ManipulateScreen and ManipulateScreen is forbidden" << endl; + kdDebug(KDESKTOP_DEBUG_ID) << "Screensaver is type ManipulateScreen and ManipulateScreen is forbidden" << endl; mForbidden = true; } if ((saverTypes[i] == "OpenGL") && !opengl) { - kdDebug(1204) << "Screensaver is type OpenGL and OpenGL is forbidden" << endl; + kdDebug(KDESKTOP_DEBUG_ID) << "Screensaver is type OpenGL and OpenGL is forbidden" << endl; mForbidden = true; } if (saverTypes[i] == "OpenGL") { @@ -794,7 +810,7 @@ void LockProcess::readSaver() } } - kdDebug(1204) << "mForbidden: " << (mForbidden ? "true" : "false") << endl; + kdDebug(KDESKTOP_DEBUG_ID) << "mForbidden: " << (mForbidden ? "true" : "false") << endl; if (trinity_desktop_lock_use_system_modal_dialogs) { if (config.hasActionGroup("InWindow")) { @@ -968,7 +984,7 @@ void LockProcess::createSaverWindow() } } - kdDebug(1204) << "Saver window Id: " << winId() << endl; + kdDebug(KDESKTOP_DEBUG_ID) << "Saver window Id: " << winId() << endl; } void LockProcess::desktopResized() @@ -1307,7 +1323,7 @@ bool LockProcess::startSaver(bool notify_ready) { if (!child_saver && !grabInput()) { - kdWarning(1204) << "LockProcess::startSaver() grabInput() failed!!!!" << endl; + kdWarning(KDESKTOP_DEBUG_ID) << "LockProcess::startSaver() grabInput() failed!!!!" << endl; return false; } mBusy = false; @@ -1393,7 +1409,7 @@ bool LockProcess::startSaver(bool notify_ready) // void LockProcess::stopSaver() { - kdDebug(1204) << "LockProcess: stopping saver" << endl; + kdDebug(KDESKTOP_DEBUG_ID) << "LockProcess: stopping saver" << endl; mHackProc.kill(SIGCONT); stopHack(); mSuspended = false; @@ -1446,30 +1462,30 @@ bool LockProcess::startLock() GreeterPluginHandle plugin; TQString path = KLibLoader::self()->findLibrary( ((*it)[0] == '/' ? *it : "kgreet_" + *it ).latin1() ); if (path.isEmpty()) { - kdWarning(1204) << "GreeterPlugin " << *it << " does not exist" << endl; + kdWarning(KDESKTOP_DEBUG_ID) << "GreeterPlugin " << *it << " does not exist" << endl; continue; } if (!(plugin.library = KLibLoader::self()->library( path.latin1() ))) { - kdWarning(1204) << "Cannot load GreeterPlugin " << *it << " (" << path << ")" << endl; + kdWarning(KDESKTOP_DEBUG_ID) << "Cannot load GreeterPlugin " << *it << " (" << path << ")" << endl; continue; } if (!plugin.library->hasSymbol( "kgreeterplugin_info" )) { - kdWarning(1204) << "GreeterPlugin " << *it << " (" << path << ") is no valid greet widget plugin" << endl; + kdWarning(KDESKTOP_DEBUG_ID) << "GreeterPlugin " << *it << " (" << path << ") is no valid greet widget plugin" << endl; plugin.library->unload(); continue; } plugin.info = (kgreeterplugin_info*)plugin.library->symbol( "kgreeterplugin_info" ); if (plugin.info->method && !mMethod.isEmpty() && mMethod != plugin.info->method) { - kdDebug(1204) << "GreeterPlugin " << *it << " (" << path << ") serves " << plugin.info->method << ", not " << mMethod << endl; + kdDebug(KDESKTOP_DEBUG_ID) << "GreeterPlugin " << *it << " (" << path << ") serves " << plugin.info->method << ", not " << mMethod << endl; plugin.library->unload(); continue; } if (!plugin.info->init( mMethod, getConf, this )) { - kdDebug(1204) << "GreeterPlugin " << *it << " (" << path << ") refuses to serve " << mMethod << endl; + kdDebug(KDESKTOP_DEBUG_ID) << "GreeterPlugin " << *it << " (" << path << ") refuses to serve " << mMethod << endl; plugin.library->unload(); continue; } - kdDebug(1204) << "GreeterPlugin " << *it << " (" << plugin.info->method << ", " << plugin.info->name << ") loaded" << endl; + kdDebug(KDESKTOP_DEBUG_ID) << "GreeterPlugin " << *it << " (" << plugin.info->method << ", " << plugin.info->name << ") loaded" << endl; greetPlugin = plugin; mLocked = true; DM().setLock( true ); @@ -1588,7 +1604,7 @@ bool LockProcess::startHack() if (!path.isEmpty()) { mHackProc << path; - kdDebug(1204) << "Starting hack: " << path << endl; + kdDebug(KDESKTOP_DEBUG_ID) << "Starting hack: " << path << endl; while (!ts.atEnd()) { ts >> word; @@ -2297,10 +2313,10 @@ void LockProcess::stayOnTop() // and stack others below it Window* stack = new Window[ mDialogs.count() + mVkbdWindows.count() + 1 ]; int count = 0; - for( TQValueList< VkbdWindow >::ConstIterator it = mVkbdWindows.begin(); it != mVkbdWindows.end(); ++it ) + for( TQValueList< VkbdWindow >::ConstIterator it = mVkbdWindows.begin(); it != mVkbdWindows.end(); ++it ) { stack[ count++ ] = (*it).id; } - for( TQValueList< TQWidget* >::ConstIterator it = mDialogs.begin(); it != mDialogs.end(); ++it ) + for( TQValueList< TQWidget* >::ConstIterator it = mDialogs.begin(); it != mDialogs.end(); ++it ) { stack[ count++ ] = (*it)->winId(); } stack[ count++ ] = winId(); @@ -2795,6 +2811,110 @@ void LockProcess::processInputPipeCommand(TQString inputcommand) { } } +void LockProcess::cryptographicCardInserted(TDECryptographicCardDevice* cdevice) { + 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()) { + // Activate appropriate VT + DM dm; + SessList sess; + if (dm.localSessions(sess)) { + TQString user, loc; + for (SessList::ConstIterator it = sess.begin(); it != sess.end(); ++it) { + DM::sess2Str2(*it, user, loc); + if ((*it).self) { + // Switch VTs + DM().switchVT((*it).vt); + break; + } + } + } + + // Pass login to the PAM stack... + if (dynamic_cast(currentDialog)) { + dynamic_cast(currentDialog)->closeDialogForced(); + TQTimer::singleShot(0, this, SLOT(signalPassDlgToAttemptCardLogin())); + } + else if (dynamic_cast(currentDialog)) { + dynamic_cast(currentDialog)->closeDialogForced(); + TQTimer::singleShot(0, this, SLOT(signalPassDlgToAttemptCardLogin())); + } + else if (dynamic_cast(currentDialog)) { + signalPassDlgToAttemptCardLogin(); + } + } + } +} + +void LockProcess::cryptographicCardRemoved(TDECryptographicCardDevice* cdevice) { + PasswordDlg* passDlg = dynamic_cast(currentDialog); + if (passDlg) { + passDlg->resetCardLogin(); + } + else { + TQTimer::singleShot(0, this, SLOT(signalPassDlgToAttemptCardAbort())); + } +} + +void LockProcess::signalPassDlgToAttemptCardLogin() { + PasswordDlg* passDlg = dynamic_cast(currentDialog); + if (passDlg) { + passDlg->attemptCardLogin(); + } + else { + if (currentDialog) { + // Try again later + TQTimer::singleShot(0, this, SLOT(signalPassDlgToAttemptCardLogin())); + } + } +} + +void LockProcess::signalPassDlgToAttemptCardAbort() { + PasswordDlg* passDlg = dynamic_cast(currentDialog); + if (passDlg) { + passDlg->resetCardLogin(); + } + else { + if (currentDialog) { + // Try again later + TQTimer::singleShot(0, this, SLOT(signalPassDlgToAttemptCardAbort())); + } + } +} + +void LockProcess::cryptographicCardPinRequested(TQString prompt, TDECryptographicCardDevice* cdevice) { + TQCString password; + const char * pin_entry; + + QueryDlg qryDlg(this); + qryDlg.updateLabel(prompt); + qryDlg.setUnlockIcon(); + mForceReject = false; + execDialog(&qryDlg); + if (mForceReject == false) { + pin_entry = qryDlg.getEntry(); + cdevice->setProvidedPin(pin_entry); + } + else { + cdevice->setProvidedPin(TQString::null); + } +} + void LockProcess::fullyOnline() { if (!mFullyOnlineSent) { if (kdesktop_pid > 0) { diff --git a/kdesktop/lock/lockprocess.h b/kdesktop/lock/lockprocess.h index ae2a71c1d..dafd2ae1c 100644 --- a/kdesktop/lock/lockprocess.h +++ b/kdesktop/lock/lockprocess.h @@ -10,6 +10,11 @@ #ifndef __LOCKENG_H__ #define __LOCKENG_H__ +#include + +#include +#include + #include #include @@ -134,6 +139,11 @@ class LockProcess : public TQWidget void startSecureDialog(); void slotMouseActivity(XEvent *event); void processInputPipeCommand(TQString command); + void cryptographicCardInserted(TDECryptographicCardDevice*); + void cryptographicCardRemoved(TDECryptographicCardDevice*); + void cryptographicCardPinRequested(TQString prompt, TDECryptographicCardDevice* cdevice); + void signalPassDlgToAttemptCardLogin(); + void signalPassDlgToAttemptCardAbort(); private: void configure(); diff --git a/kdesktop/lock/main.cc b/kdesktop/lock/main.cc index e82650928..6937cbe6a 100644 --- a/kdesktop/lock/main.cc +++ b/kdesktop/lock/main.cc @@ -372,15 +372,23 @@ int main( int argc, char **argv ) KSimpleConfig* tdmconfig; OPEN_TDMCONFIG_AND_SET_GROUP + sigset_t new_mask; + sigset_t orig_mask; + + // Block reception of all signals in this thread + sigprocmask(SIG_BLOCK, &new_mask, NULL); + + // Create new LockProcess, which also spawns threads inheriting the blocked signal mask trinity_desktop_lock_process = new LockProcess; + // Unblock reception of all signals in this thread + sigprocmask(SIG_UNBLOCK, &new_mask, NULL); + // Start loading core functions, such as the desktop wallpaper interface app->processEvents(); if (args->isSet( "internal" )) { kdesktop_pid = atoi(args->getOption( "internal" )); - sigset_t new_mask; - sigset_t orig_mask; struct sigaction act; in_internal_mode = TRUE; diff --git a/kdesktop/lockeng.cc b/kdesktop/lockeng.cc index 600573f27..ceffd73f0 100644 --- a/kdesktop/lockeng.cc +++ b/kdesktop/lockeng.cc @@ -11,10 +11,16 @@ #include +#include + +#include +#include + #include #include #include #include +#include #include #include #include @@ -82,6 +88,7 @@ SaverEngine::SaverEngine() mTerminationRequested(false), mSaverProcessReady(false), mNewVTAfterLockEngage(false), + mValidCryptoCardInserted(false), mSwitchVTAfterLockEngage(-1), dBusLocal(0), dBusWatch(0), @@ -158,6 +165,17 @@ SaverEngine::SaverEngine() sigaddset(&mThreadBlockSet, SIGTTIN); pthread_sigmask(SIG_BLOCK, &mThreadBlockSet, NULL); + // 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(hwdevice); + connect(cdevice, TQT_SIGNAL(certificateListAvailable(TDECryptographicCardDevice*)), this, TQT_SLOT(cryptographicCardInserted(TDECryptographicCardDevice*))); + connect(cdevice, TQT_SIGNAL(cardRemoved(TDECryptographicCardDevice*)), this, TQT_SLOT(cryptographicCardRemoved(TDECryptographicCardDevice*))); + cdevice->enableCardMonitoring(true); + } + dBusConnect(); } @@ -186,6 +204,43 @@ SaverEngine::~SaverEngine() delete m_helperThread; } +void SaverEngine::cryptographicCardInserted(TDECryptographicCardDevice* cdevice) { + 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; + // Disable saver + enable(false); + } + } +} + +void SaverEngine::cryptographicCardRemoved(TDECryptographicCardDevice* cdevice) { + if (mValidCryptoCardInserted) { + // Restore saver timeout + configure(); + + // Force lock + lockScreen(); + } + mValidCryptoCardInserted = false; +} + //--------------------------------------------------------------------------- // // This should be called only using DCOP. @@ -283,28 +338,25 @@ bool SaverEngine::enable( bool e ) mEnabled = e; - if (mEnabled) - { + if (mEnabled) { if ( !mXAutoLock ) { mXAutoLock = new XAutoLock(); connect(mXAutoLock, TQT_SIGNAL(timeout()), TQT_SLOT(idleTimeout())); } - mXAutoLock->setTimeout(mTimeout); - mXAutoLock->setDPMS(true); + mXAutoLock->setTimeout(mTimeout); + mXAutoLock->setDPMS(true); //mXAutoLock->changeCornerLockStatus( mLockCornerTopLeft, mLockCornerTopRight, mLockCornerBottomLeft, mLockCornerBottomRight); - // We'll handle blanking - XSetScreenSaver(tqt_xdisplay(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures); - kdDebug() << "XSetScreenSaver " << mTimeout + 10 << endl; - - mXAutoLock->start(); - - kdDebug(1204) << "Saver Engine started, timeout: " << mTimeout << endl; + // We'll handle blanking + XSetScreenSaver(tqt_xdisplay(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures); + kdDebug() << "XSetScreenSaver " << mTimeout + 10 << endl; + + mXAutoLock->start(); + + kdDebug(1204) << "Saver Engine started, timeout: " << mTimeout << endl; } - else - { - if (mXAutoLock) - { + else { + if (mXAutoLock) { delete mXAutoLock; mXAutoLock = 0; } diff --git a/kdesktop/lockeng.h b/kdesktop/lockeng.h index 166d6b40e..5eebaa472 100644 --- a/kdesktop/lockeng.h +++ b/kdesktop/lockeng.h @@ -18,6 +18,7 @@ #include +class TDECryptographicCardDevice; class DCOPClientTransaction; class TQT_DBusMessage; class TQT_DBusProxy; @@ -134,6 +135,9 @@ private slots: void handleSecureDialog(); void slotSAKProcessExited(); + void cryptographicCardInserted(TDECryptographicCardDevice*); + void cryptographicCardRemoved(TDECryptographicCardDevice*); + /** * Enable wallpaper exports */ @@ -186,6 +190,7 @@ private: bool mTerminationRequested; bool mSaverProcessReady; bool mNewVTAfterLockEngage; + bool mValidCryptoCardInserted; int mSwitchVTAfterLockEngage; struct sigaction mSignalAction; TQT_DBusConnection dBusConn; diff --git a/tdm/CMakeLists.txt b/tdm/CMakeLists.txt index 08096f84c..ce8a1f4ed 100644 --- a/tdm/CMakeLists.txt +++ b/tdm/CMakeLists.txt @@ -21,3 +21,4 @@ include( ConfigureChecks.cmake ) add_subdirectory( backend ) add_subdirectory( kfrontend ) +add_subdirectory( cryptocardwatcher ) diff --git a/tdm/backend/client.c b/tdm/backend/client.c index cb185bca1..2676a5d2a 100644 --- a/tdm/backend/client.c +++ b/tdm/backend/client.c @@ -180,7 +180,7 @@ PAM_conv( int num_msg, ReInitErrorLog(); Debug( "PAM_conv\n" ); - for (count = 0; count < num_msg; count++) + for (count = 0; count < num_msg; count++) { switch (msg[count]->msg_style) { case PAM_TEXT_INFO: Debug( " PAM_TEXT_INFO: %s\n", msg[count]->msg ); @@ -201,9 +201,18 @@ PAM_conv( int num_msg, /* case PAM_PROMPT_ECHO_ON: cannot happen */ case PAM_PROMPT_ECHO_OFF: Debug( " PAM_PROMPT_ECHO_OFF (usecur): %s\n", msg[count]->msg ); - if (!curpass) - pd->gconv( GCONV_PASS, 0 ); - StrDup( &reply[count].resp, curpass ); + // WARNING + // This is far from foolproof, but it's the best we can do at this time... + // Try to detect PIN entry requests + if (strstr(msg[count]->msg, "PIN")) { + reply[count].resp = pd->gconv(GCONV_HIDDEN, msg[count]->msg); + } + else { + if (!curpass) { + pd->gconv( GCONV_PASS, 0 ); + } + StrDup( &reply[count].resp, curpass ); + } break; default: LogError( "Unknown PAM message style <%d>\n", msg[count]->msg_style ); @@ -237,6 +246,7 @@ PAM_conv( int num_msg, } reply[count].resp_retcode = PAM_SUCCESS; /* unused in linux-pam */ } + } Debug( " PAM_conv success\n" ); *resp = reply; return PAM_SUCCESS; @@ -769,7 +779,6 @@ Verify( GConvFunc gconv, int rootok ) } #ifdef USE_PAM - Debug( " pam_acct_mgmt() ...\n" ); pretc = pam_acct_mgmt( pamh, 0 ); ReInitErrorLog(); diff --git a/tdm/cryptocardwatcher/CMakeLists.txt b/tdm/cryptocardwatcher/CMakeLists.txt new file mode 100644 index 000000000..7564ac2cf --- /dev/null +++ b/tdm/cryptocardwatcher/CMakeLists.txt @@ -0,0 +1,32 @@ +################################################# +# +# (C) 2015 Timothy Pearson +# kb9vqf (AT) pearsoncomputing.net +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/tdmlib + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + + +##### tdecryptocardwatcher (executable) ######### + +tde_add_executable( tdecryptocardwatcher AUTOMOC + SOURCES main.cpp watcher.cc + LINK tdecore-shared tdeio-shared dmctl-static + DESTINATION ${BIN_INSTALL_DIR} + SETUID +) + diff --git a/tdm/cryptocardwatcher/main.cpp b/tdm/cryptocardwatcher/main.cpp new file mode 100644 index 000000000..5d27ff19b --- /dev/null +++ b/tdm/cryptocardwatcher/main.cpp @@ -0,0 +1,139 @@ +/* + * Copyright 2015 Timothy Pearson + * + * This file is part of cryptocardwatcher, the TDE Cryptographic Card Session Monitor + * + * cryptocardwatcher 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 3 + * of the License, or (at your option) any later version. + * + * cryptocardwatcher 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 cryptocardwatcher. If not, see http://www.gnu.org/licenses/. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +#include "watcher.h" + +int lockfd = -1; +char lockFileName[256]; + +// -------------------------------------------------------------------------------------- +// Useful function from Stack Overflow +// http://stackoverflow.com/questions/1599459/optimal-lock-file-method +// -------------------------------------------------------------------------------------- +int tryGetLock(char const *lockName) { + mode_t m = umask( 0 ); + int fd = open( lockName, O_RDWR|O_CREAT, 0666 ); + umask( m ); + if( fd >= 0 && flock( fd, LOCK_EX | LOCK_NB ) < 0 ) { + close( fd ); + fd = -1; + } + return fd; +} +// -------------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------------- +// Useful function from Stack Overflow +// http://stackoverflow.com/questions/1599459/optimal-lock-file-method +// -------------------------------------------------------------------------------------- +void releaseLock(int fd, char const *lockName) { + if( fd < 0 ) { + return; + } + remove( lockName ); + close( fd ); +} +// -------------------------------------------------------------------------------------- + +void handle_sigterm(int signum) { + if (lockfd >= 0) { + releaseLock(lockfd, lockFileName); + } + exit(0); +} + +static TDECmdLineOptions options[] = +{ + TDECmdLineLastOption +}; + +int main(int argc, char *argv[]) { + int ret = -1; + + // Register cleanup handlers + struct sigaction action; + memset(&action, 0, sizeof(struct sigaction)); + action.sa_handler = handle_sigterm; + sigaction(SIGTERM, &action, NULL); + + // Ensure only one process is running + sprintf(lockFileName, "/var/lock/cryptocardwatcher.lock"); + lockfd = tryGetLock(lockFileName); + if (lockfd < 0) { + printf ("[cryptocardwatcher] Another instance of this program is already running!\n[cryptocardwatcher] Lockfile detected at '%s'\n", lockFileName); + return -2; + } + + // Parse command line arguments + TDECmdLineArgs::init(argc, argv, "cryptocardwatcher", "cryptocardwatcher", "TDE Cryptographic Card Session Monitor", "0.1"); + TDECmdLineArgs::addCmdLineOptions(options); + TDEApplication::addCmdLineOptions(); + + // Initialize TDE application + TDEApplication tdeapp(false, false); + tdeapp.disableAutoDcopRegistration(); + CardWatcher* watcher = new CardWatcher(); + + // 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(hwdevice); + TQObject::connect(cdevice, TQT_SIGNAL(cardInserted(TDECryptographicCardDevice*)), watcher, TQT_SLOT(cryptographicCardInserted(TDECryptographicCardDevice*))); + TQObject::connect(cdevice, TQT_SIGNAL(cardRemoved(TDECryptographicCardDevice*)), watcher, TQT_SLOT(cryptographicCardRemoved(TDECryptographicCardDevice*))); + cdevice->enableCardMonitoring(true); + } + + // Start TDE application + ret = tdeapp.exec(); + + // Clean up + delete watcher; + + releaseLock(lockfd, lockFileName); + return ret; +} diff --git a/tdm/cryptocardwatcher/watcher.cc b/tdm/cryptocardwatcher/watcher.cc new file mode 100644 index 000000000..e25821183 --- /dev/null +++ b/tdm/cryptocardwatcher/watcher.cc @@ -0,0 +1,86 @@ +/* + * Copyright 2015 Timothy Pearson + * + * This file is part of cryptocardwatcher, the TDE Cryptographic Card Session Monitor + * + * cryptocardwatcher 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 3 + * of the License, or (at your option) any later version. + * + * cryptocardwatcher 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 cryptocardwatcher. If not, see http://www.gnu.org/licenses/. + */ + +#include "watcher.h" + +#include + +#include +#include + +#include +#include + +CardWatcher::CardWatcher() : TQObject() { + // +} + +CardWatcher::~CardWatcher() { + // +} + +void CardWatcher::cryptographicCardInserted(TDECryptographicCardDevice* cdevice) { + 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 != "") { + // Determine if user already has an active session + DM dm; + SessList sess; + bool user_active = false; + if (dm.localSessions(sess)) { + TQString user, loc; + for (SessList::ConstIterator it = sess.begin(); it != sess.end(); ++it) { + DM::sess2Str2(*it, user, loc); + if (user.startsWith(login_name + ": ")) { + // Found active session + user_active = true; + } + if (user == "Unused") { + if ((*it).vt == dm.activeVT()) { + // Found active unused session + user_active = true; + } + } + } + } + if (!user_active) { + // Activate new VT + DM().startReserve(); + } + } +} + +void CardWatcher::cryptographicCardRemoved(TDECryptographicCardDevice* cdevice) { + // +} + +#include "watcher.moc" \ No newline at end of file diff --git a/tdm/cryptocardwatcher/watcher.h b/tdm/cryptocardwatcher/watcher.h new file mode 100644 index 000000000..bfbb010a0 --- /dev/null +++ b/tdm/cryptocardwatcher/watcher.h @@ -0,0 +1,40 @@ +/* + * Copyright 2015 Timothy Pearson + * + * This file is part of cryptocardwatcher, the TDE Cryptographic Card Session Monitor + * + * cryptocardwatcher 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 3 + * of the License, or (at your option) any later version. + * + * cryptocardwatcher 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 cryptocardwatcher. If not, see http://www.gnu.org/licenses/. + */ + +#ifndef __TDECRYPTOCARDWATCHER_H__ +#define __TDECRYPTOCARDWATCHER_H__ + +#include + +class TDECryptographicCardDevice; + +class CardWatcher : public TQObject +{ + Q_OBJECT + + public: + CardWatcher(); + ~CardWatcher(); + + public slots: + void cryptographicCardInserted(TDECryptographicCardDevice*); + void cryptographicCardRemoved(TDECryptographicCardDevice*); +}; + +#endif // __TDECRYPTOCARDWATCHER_H__ \ No newline at end of file diff --git a/tdm/kfrontend/CMakeLists.txt b/tdm/kfrontend/CMakeLists.txt index 8c0fffd5c..ab2ddc691 100644 --- a/tdm/kfrontend/CMakeLists.txt +++ b/tdm/kfrontend/CMakeLists.txt @@ -68,7 +68,7 @@ tde_add_executable( tdm_greet AUTOMOC kfdialog.cpp kgdialog.cpp kchooser.cpp kgverify.cpp tdmshutdown.cpp tdmadmindialog.cpp kgreeter.cpp kgapp.cpp sakdlg.cc - LINK tdmthemer-static tdeui-shared Xtst ${TDMGREET_OPTIONAL_LINK} + LINK tdmthemer-static tdeui-shared tdeio-shared dmctl-static Xtst ${TDMGREET_OPTIONAL_LINK} DESTINATION ${BIN_INSTALL_DIR} ) diff --git a/tdm/kfrontend/kgapp.cpp b/tdm/kfrontend/kgapp.cpp index 2d630485e..65e6cf0d8 100644 --- a/tdm/kfrontend/kgapp.cpp +++ b/tdm/kfrontend/kgapp.cpp @@ -72,6 +72,7 @@ bool has_twin = false; bool is_themed = false; bool trinity_desktop_lock_use_sak = TRUE; bool trinity_desktop_synchronize_keyboard_lights = TRUE; +bool trinity_desktop_watch_cryptographic_cards = TRUE; TQPoint primaryScreenPosition; static int @@ -216,6 +217,7 @@ kg_main( const char *argv0 ) TDEProcess *tsak = 0; TDEProcess *kbdl = 0; + TDEProcess *ccsm = 0; TDEProcess *proc = 0; TDEProcess *comp = 0; TDEProcess *dcop = 0; @@ -252,6 +254,12 @@ kg_main( const char *argv0 ) kbdl->start(); } + if (trinity_desktop_watch_cryptographic_cards) { + ccsm = new TDEProcess; + *ccsm << TQCString( argv0, strrchr( argv0, '/' ) - argv0 + 2 ) + "tdecryptocardwatcher"; + ccsm->start(); + } + XSetErrorHandler( ignoreXError ); argb_visual_available = false; char *display = 0; @@ -518,6 +526,10 @@ kg_main( const char *argv0 ) kbdl->closeStdin(); kbdl->detach(); } + if (ccsm) { + ccsm->closeStdin(); + ccsm->detach(); + } if (comp) { if (comp->isRunning()) { if (_compositor == TDE_COMPOSITOR_BINARY) { diff --git a/tdm/kfrontend/kgreeter.cpp b/tdm/kfrontend/kgreeter.cpp index aa89fd78e..d3ee07de6 100644 --- a/tdm/kfrontend/kgreeter.cpp +++ b/tdm/kfrontend/kgreeter.cpp @@ -33,6 +33,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "themer/tdmitem.h" #include "themer/tdmlabel.h" +#include + +#include + +#include +#include + #include #include #include @@ -212,6 +219,17 @@ KGreeter::KGreeter( bool framed ) pluginList = KGVerify::init( _pluginsLogin ); } + // 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(hwdevice); + connect(cdevice, TQT_SIGNAL(certificateListAvailable(TDECryptographicCardDevice*)), this, TQT_SLOT(cryptographicCardInserted(TDECryptographicCardDevice*))); + connect(cdevice, TQT_SIGNAL(cardRemoved(TDECryptographicCardDevice*)), this, TQT_SLOT(cryptographicCardRemoved(TDECryptographicCardDevice*))); + cdevice->enableCardMonitoring(true); + } + mControlPipeHandlerThread = new TQEventLoopThread(); mControlPipeHandler = new ControlPipeHandlerObject(); mControlPipeHandler->mKGreeterParent = this; @@ -829,6 +847,60 @@ KGreeter::verifySetUser( const TQString &user ) slotUserEntered(); } +void KGreeter::cryptographicCardInserted(TDECryptographicCardDevice* cdevice) { + 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 != "") { + DM dm; + SessList sess; + bool vt_active = false; + bool user_active = false; + if (dm.localSessions(sess)) { + TQString user, loc; + for (SessList::ConstIterator it = sess.begin(); it != sess.end(); ++it) { + DM::sess2Str2(*it, user, loc); + if (user.startsWith(login_name + ": ")) { + // Found active session + user_active = true; + } + if ((*it).self) { + if ((*it).vt == dm.activeVT()) { + vt_active = true; + } + } + } + } + + if (!user_active && vt_active) { + // Select the correct user + verify->setUser(login_name); + verifySetUser(login_name); + verify->lockUserEntry(true); + + // Initiate login + verify->accept(); + } + } +} + +void KGreeter::cryptographicCardRemoved(TDECryptographicCardDevice* cdevice) { + verify->lockUserEntry(false); + verify->requestAbort(); +} + KStdGreeter::KStdGreeter() : KGreeter() , clock( 0 ) diff --git a/tdm/kfrontend/kgreeter.h b/tdm/kfrontend/kgreeter.h index 7d1c1bc6f..fa24622d0 100644 --- a/tdm/kfrontend/kgreeter.h +++ b/tdm/kfrontend/kgreeter.h @@ -46,6 +46,8 @@ class TQListViewItem; class KGreeter; class SAKDlg; +class TDECryptographicCardDevice; + struct SessType { TQString name, type; bool hid; @@ -138,6 +140,8 @@ class KGreeter : public KGDialog, public KGVerifyHandler { private slots: void slotLoadPrevWM(); + void cryptographicCardInserted(TDECryptographicCardDevice*); + void cryptographicCardRemoved(TDECryptographicCardDevice*); private: ControlPipeHandlerObject* mControlPipeHandler; diff --git a/tdm/kfrontend/kgverify.cpp b/tdm/kfrontend/kgverify.cpp index 46b89e9c5..a02cc1c39 100644 --- a/tdm/kfrontend/kgverify.cpp +++ b/tdm/kfrontend/kgverify.cpp @@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "themer/tdmthemer.h" #include "themer/tdmitem.h" +#include "themer/tdmlabel.h" #include #include @@ -66,30 +67,31 @@ void KGVerifyHandler::updateStatus( bool, bool, int ) { } -KGVerify::KGVerify( KGVerifyHandler *_handler, KdmThemer *_themer, - TQWidget *_parent, TQWidget *_predecessor, - const TQString &_fixedUser, - const PluginList &_pluginList, - KGreeterPlugin::Function _func, - KGreeterPlugin::Context _ctx ) +KGVerify::KGVerify(KGVerifyHandler *_handler, KdmThemer *_themer, + TQWidget *_parent, TQWidget *_predecessor, + const TQString &_fixedUser, + const PluginList &_pluginList, + KGreeterPlugin::Function _func, + KGreeterPlugin::Context _ctx) : inherited() - , coreLock( 0 ) - , fixedEntity( _fixedUser ) - , pluginList( _pluginList ) - , handler( _handler ) - , themer( _themer ) - , parent( _parent ) - , predecessor( _predecessor ) - , plugMenu( 0 ) - , curPlugin( -1 ) - , timedLeft( 0 ) - , func( _func ) - , ctx( _ctx ) - , enabled( true ) - , running( false ) - , suspended( false ) - , failed( false ) - , isClear( true ) + , coreLock(0) + , fixedEntity(_fixedUser) + , pluginList(_pluginList) + , handler(_handler) + , themer(_themer) + , parent(_parent) + , predecessor(_predecessor) + , plugMenu(0) + , curPlugin(-1) + , timedLeft(0) + , func(_func) + , ctx(_ctx) + , enabled(true) + , running(false) + , suspended(false) + , failed(false) + , isClear(true) + , abortRequested(false) { connect( &timer, TQT_SIGNAL(timeout()), TQT_SLOT(slotTimeout()) ); connect( kapp, TQT_SIGNAL(activity()), TQT_SLOT(slotActivity()) ); @@ -268,6 +270,14 @@ KGVerify::setUser( const TQString &user ) gplugActivity(); } +void +KGVerify::lockUserEntry(const bool lock) +{ + // assert( fixedEntity.isEmpty() ); + Debug( "%s->lockUserEntry(%\"s)\n", pName.data(), lock ); + greet->lockUserEntry(lock); +} + void KGVerify::setPassword( const TQString &pass ) { @@ -374,6 +384,12 @@ KGVerify::reject() doReject( true ); } +void // not a slot - called manually by greeter +KGVerify::requestAbort() +{ + abortRequested = true; +} + void KGVerify::setEnabled( bool on ) { @@ -478,27 +494,28 @@ KGVerify::VErrBox( TQWidget *parent, const TQString &user, const char *msg ) } void // private static -KGVerify::VInfoBox( TQWidget *parent, const TQString &user, const char *msg ) +KGVerify::VInfoBox(TQWidget *parent, const TQString &user, const char *msg) { TQString mesg = TQString::fromLocal8Bit( msg ); TQRegExp rx( "^Warning: your account will expire in (\\d+) day" ); - if (rx.search( mesg ) >= 0) { - int expire = rx.cap( 1 ).toInt(); + if (rx.search(mesg) >= 0) { + int expire = rx.cap(1).toInt(); mesg = expire ? i18n("Your account expires tomorrow.", "Your account expires in %n days.", expire) : i18n("Your account expires today."); - } else { + } + else { rx.setPattern( "^Warning: your password will expire in (\\d+) day" ); - if (rx.search( mesg ) >= 0) { - int expire = rx.cap( 1 ).toInt(); + if (rx.search(mesg) >= 0) { + int expire = rx.cap(1).toInt(); mesg = expire ? i18n("Your password expires tomorrow.", "Your password expires in %n days.", expire) : i18n("Your password expires today."); } } - VMsgBox( parent, user, infobox, mesg ); + VMsgBox(parent, user, infobox, mesg); } bool // public static @@ -597,9 +614,24 @@ KGVerify::handleVerify() Debug( " echo = %d\n", echo ); ndelay = GRecvInt(); Debug( " ndelay = %d\n%s->textPrompt(...)\n", ndelay, pName.data() ); - greet->textPrompt( msg, echo, ndelay ); - if (msg) - free( msg ); + if (abortRequested) { + greet->textPrompt("", echo, ndelay); + abortRequested = false; + } + else { + if (msg && (msg[0] != 0)) { + // Reset password entry and change text + setPassPromptText(msg); + greet->start(); + greet->textPrompt(msg, echo, ndelay); + } + else { + greet->textPrompt(msg, echo, ndelay); + } + } + if (msg) { + free(msg); + } return; case V_GET_BINARY: Debug( " V_GET_BINARY\n" ); @@ -607,9 +639,16 @@ KGVerify::handleVerify() Debug( " %d bytes prompt\n", ret ); ndelay = GRecvInt(); Debug( " ndelay = %d\n%s->binaryPrompt(...)\n", ndelay, pName.data() ); - greet->binaryPrompt( msg, ndelay ); - if (msg) - free( msg ); + if (abortRequested) { + gplugReturnBinary(NULL); + abortRequested = false; + } + else { + greet->binaryPrompt( msg, ndelay ); + } + if (msg) { + free(msg); + } return; } @@ -622,11 +661,12 @@ KGVerify::handleVerify() curUser = user = TQString::fromLocal8Bit( msg ); // greet needs this to be able to return something useful from // getEntity(). but the backend is still unable to tell a domain ... - Debug( " %s->setUser(%\"s)\n", pName.data(), user.latin1() ); + Debug(" %s->setUser(%\"s)\n", pName.data(), user.latin1()); greet->setUser( curUser ); - handler->verifySetUser( curUser ); - if (msg) - free( msg ); + handler->verifySetUser(curUser); + if (msg) { + free(msg); + } continue; case V_PRE_OK: // this is only for func == AuthChAuthTok Debug( " V_PRE_OK\n" ); @@ -636,8 +676,9 @@ KGVerify::handleVerify() // is not implemented yet. authTok = true; cont = true; - Debug( "%s->succeeded()\n", pName.data() ); + Debug("%s->succeeded()\n", pName.data()); greet->succeeded(); + abortRequested = false; continue; case V_CHTOK_AUTH: Debug( " V_CHTOK_AUTH\n" ); @@ -648,14 +689,16 @@ KGVerify::handleVerify() Debug( " V_CHTOK\n" ); nfunc = KGreeterPlugin::ChAuthTok; user = TQString::null; - dchtok: + dchtok: { timer.stop(); Debug( "%s->succeeded()\n", pName.data() ); greet->succeeded(); + abortRequested = false; KGChTok chtok( parent, user, pluginList, curPlugin, nfunc, KGreeterPlugin::Login ); - if (!chtok.exec()) + if (!chtok.exec()) { goto retry; + } handler->verifyOk(); return; } @@ -665,11 +708,16 @@ KGVerify::handleVerify() Debug( " %s->textMessage(%\"s, true)\n", pName.data(), msg ); if (!greet->textMessage( msg, true )) { Debug( " message passed\n" ); - VErrBox( parent, user, msg ); - } else + if (!abortRequested) { + VErrBox( parent, user, msg ); + } + } + else { Debug( " message swallowed\n" ); - if (msg) - free( msg ); + } + if (msg) { + free(msg); + } continue; case V_MSG_INFO: Debug( " V_MSG_INFO\n" ); @@ -677,10 +725,14 @@ KGVerify::handleVerify() Debug( " %s->textMessage(%\"s, false)\n", pName.data(), msg ); if (!greet->textMessage( msg, false )) { Debug( " message passed\n" ); - VInfoBox( parent, user, msg ); - } else - Debug( " message swallowed\n" ); - free( msg ); + if (!abortRequested) { + VInfoBox(parent, user, msg); + } + } + else { + Debug(" message swallowed\n"); + } + free(msg); continue; } @@ -698,6 +750,7 @@ KGVerify::handleVerify() if (ent != fixedEntity) { Debug( "%s->failed()\n", pName.data() ); greet->failed(); + abortRequested = false; MsgBox( sorrybox, i18n("Authenticated user (%1) does not match requested user (%2).\n") .arg( ent ).arg( fixedEntity ) ); @@ -706,12 +759,17 @@ KGVerify::handleVerify() } Debug( "%s->succeeded()\n", pName.data() ); greet->succeeded(); + abortRequested = false; handler->verifyOk(); return; } Debug( "%s->failed()\n", pName.data() ); greet->failed(); + abortRequested = false; + + // Reset password prompt text + setPassPromptText(TQString::null, true); if (ret == V_AUTH) { Debug( " V_AUTH\n" ); @@ -736,17 +794,36 @@ KGVerify::handleVerify() } } +void KGVerify::setPassPromptText(TQString text, bool use_default_text) { + if (themer) { + KdmItem* password_label = themer->findNode("password-label"); + if (password_label) { + KdmLabel* pass_label = static_cast(password_label); + if (use_default_text) { + pass_label->setText(pass_label->lookupStock("password-label")); + } + else { + pass_label->setText(text); + } + pass_label->update(); + themer->updateGeometry(true); + static_cast(themer->parent())->repaint(true); + } + } +} + void KGVerify::gplugReturnText( const char *text, int tag ) { - Debug( "%s: gplugReturnText(%\"s, %d)\n", pName.data(), - tag & V_IS_SECRET ? "" : text, tag ); - GSendStr( text ); + Debug("%s: gplugReturnText(%\"s, %d)\n", pName.data(), tag & V_IS_SECRET ? "" : text, tag); + GSendStr(text); if (text) { - GSendInt( tag ); + GSendInt(tag); handleVerify(); - } else + } + else { coreLock = 0; + } } void @@ -755,12 +832,13 @@ KGVerify::gplugReturnBinary( const char *data ) if (data) { unsigned const char *up = (unsigned const char *)data; int len = up[3] | (up[2] << 8) | (up[1] << 16) | (up[0] << 24); - Debug( "%s: gplugReturnBinary(%d bytes)\n", pName.data(), len ); - GSendArr( len, data ); + Debug("%s: gplugReturnBinary(%d bytes)\n", pName.data(), len); + GSendArr(len, data); handleVerify(); - } else { - Debug( "%s: gplugReturnBinary(NULL)\n", pName.data() ); - GSendArr( 0, 0 ); + } + else { + Debug("%s: gplugReturnBinary(NULL)\n", pName.data()); + GSendArr(0, 0); coreLock = 0; } } diff --git a/tdm/kfrontend/kgverify.h b/tdm/kfrontend/kgverify.h index 44fab973a..7db52f2ab 100644 --- a/tdm/kfrontend/kgverify.h +++ b/tdm/kfrontend/kgverify.h @@ -100,6 +100,7 @@ class KGVerify : public TQObject, public KGreeterPluginHandler { void presetEntity( const TQString &entity, int field ); TQString getEntity() const; void setUser( const TQString &user ); + void lockUserEntry( const bool lock ); void setPassword( const TQString &pass ); /* virtual */ void selectPlugin( int id ); bool entitiesLocal() const; @@ -113,6 +114,7 @@ class KGVerify : public TQObject, public KGreeterPluginHandler { void resume(); void accept(); void reject(); + void requestAbort(); int coreLock; @@ -146,6 +148,7 @@ class KGVerify : public TQObject, public KGreeterPluginHandler { bool capsLocked; bool enabled, running, suspended, failed, delayed, cont; bool authTok, isClear, timeable; + bool abortRequested; static void VMsgBox( TQWidget *parent, const TQString &user, TQMessageBox::Icon type, const TQString &mesg ); static void VErrBox( TQWidget *parent, const TQString &user, const char *msg ); @@ -158,6 +161,7 @@ class KGVerify : public TQObject, public KGreeterPluginHandler { void performAutoLogin(); bool scheduleAutoLogin( bool initial ); void doReject( bool initial ); + void setPassPromptText(TQString text, bool use_default_text=false); private slots: //virtual void slotPluginSelected( int id ) = 0; diff --git a/tdm/kfrontend/themer/tdmitem.cpp b/tdm/kfrontend/themer/tdmitem.cpp index f5eabdb56..26a4887c1 100644 --- a/tdm/kfrontend/themer/tdmitem.cpp +++ b/tdm/kfrontend/themer/tdmitem.cpp @@ -204,6 +204,22 @@ KdmItem::findNode( const TQString &_id ) const return 0; } +KdmItem * +KdmItem::findNodeByType( const TQString &_type ) const +{ + if (itemType == _type) + return const_cast( this ); + + TQValueList::ConstIterator it; + for (it = m_children.begin(); it != m_children.end(); ++it) { + KdmItem *t = (*it)->findNodeByType( _type ); + if (t) + return t; + } + + return 0; +} + void KdmItem::setWidget( TQWidget *widget ) { @@ -336,11 +352,6 @@ KdmItem::paint( TQPainter *p, const TQRect &rect ) else { // We have compositing support! TQRgb blend_color = tqRgba(m_backgroundModifier, m_backgroundModifier, m_backgroundModifier, 0); // RGBA overlay - float alpha = tqAlpha(blend_color) / 255.; - int pixel = tqAlpha(blend_color) << 24 | - int(tqRed(blend_color) * alpha) << 16 | - int(tqGreen(blend_color) * alpha) << 8 | - int(tqBlue(blend_color) * alpha); TQImage img( myWidget->size(), 32 ); img = img.convertDepth(32); diff --git a/tdm/kfrontend/themer/tdmitem.h b/tdm/kfrontend/themer/tdmitem.h index be7fa65d3..d2aeed69c 100644 --- a/tdm/kfrontend/themer/tdmitem.h +++ b/tdm/kfrontend/themer/tdmitem.h @@ -152,6 +152,7 @@ public: } KdmItem *findNode( const TQString &id ) const; + KdmItem *findNodeByType( const TQString &type ) const; virtual void setWidget( TQWidget *widget ); TQWidget *widget() const { return myWidget; } virtual void setLayoutItem( TQLayoutItem *item ); diff --git a/tdm/kfrontend/themer/tdmlabel.h b/tdm/kfrontend/themer/tdmlabel.h index 8b955fca5..e45d68091 100644 --- a/tdm/kfrontend/themer/tdmlabel.h +++ b/tdm/kfrontend/themer/tdmlabel.h @@ -40,6 +40,9 @@ public: KdmLabel( KdmItem *parent, const TQDomNode &node, const char *name = 0 ); void setText( const TQString &txt ); + /* Method to lookup the caption associated with an item */ + TQString lookupStock( const TQString &stock ); + protected: // reimplemented; returns the minimum size of rendered text virtual TQSize sizeHint(); @@ -71,9 +74,6 @@ public slots: void slotAccel(); private: - /* Method to lookup the caption associated with an item */ - TQString lookupStock( const TQString &stock ); - /* Lookup variables in the text */ TQString lookupText( const TQString &t ); diff --git a/tdm/kfrontend/themer/tdmthemer.cpp b/tdm/kfrontend/themer/tdmthemer.cpp index d6d051cf8..6c27b7629 100644 --- a/tdm/kfrontend/themer/tdmthemer.cpp +++ b/tdm/kfrontend/themer/tdmthemer.cpp @@ -117,6 +117,12 @@ KdmThemer::findNode( const TQString &item ) const return rootItem->findNode( item ); } +KdmItem * +KdmThemer::findNodeByType( const TQString &item ) const +{ + return rootItem->findNodeByType( item ); +} + void KdmThemer::updateGeometry( bool force ) { diff --git a/tdm/kfrontend/themer/tdmthemer.h b/tdm/kfrontend/themer/tdmthemer.h index 2b8865b4d..785a116da 100644 --- a/tdm/kfrontend/themer/tdmthemer.h +++ b/tdm/kfrontend/themer/tdmthemer.h @@ -72,6 +72,7 @@ public: virtual // just to put the reference in the vmt KdmItem *findNode( const TQString & ) const; + KdmItem *findNodeByType( const TQString & ) const; void updateGeometry( bool force ); // force = true for external calls diff --git a/tdm/kfrontend/themes/circles/circles.xml b/tdm/kfrontend/themes/circles/circles.xml index 0596e0ee7..102cae7b7 100644 --- a/tdm/kfrontend/themes/circles/circles.xml +++ b/tdm/kfrontend/themes/circles/circles.xml @@ -165,13 +165,13 @@ - + - + diff --git a/tdm/kfrontend/themes/minimalist/minimalist.xml b/tdm/kfrontend/themes/minimalist/minimalist.xml index f1dfada8f..dd9036799 100644 --- a/tdm/kfrontend/themes/minimalist/minimalist.xml +++ b/tdm/kfrontend/themes/minimalist/minimalist.xml @@ -37,7 +37,7 @@ - + @@ -58,7 +58,7 @@ - + diff --git a/tdm/kfrontend/themes/o2_enterprise/enterprise.xml b/tdm/kfrontend/themes/o2_enterprise/enterprise.xml index 39f159b00..11b87ae03 100644 --- a/tdm/kfrontend/themes/o2_enterprise/enterprise.xml +++ b/tdm/kfrontend/themes/o2_enterprise/enterprise.xml @@ -54,12 +54,12 @@ - + - + diff --git a/tdmlib/dmctl.cpp b/tdmlib/dmctl.cpp index 75e88fc6e..00c3cb489 100644 --- a/tdmlib/dmctl.cpp +++ b/tdmlib/dmctl.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -37,8 +38,34 @@ #include #include +#include + +static TQString readcfg(const char *cfg_file) { + TQString ctl = "/var/run/xdmctl"; + + TQStringList lines; + TQFile file(cfg_file); + if ( file.open( IO_ReadOnly ) ) { + TQTextStream stream(&file); + TQString line; + while ( !stream.atEnd() ) { + line = stream.readLine(); + TQStringList keyvaluepair = TQStringList::split("=", line, false); + if (keyvaluepair.count() > 1) { + if (keyvaluepair[0].lower() == "FifoDir") { + ctl = keyvaluepair[1]; + } + } + } + file.close(); + } + + return ctl; +} + static int DMType = DM::Unknown; -static const char *ctl, *dpy; +static const char *dpy; +static TQString ctl; DM::DM() : fd( -1 ) { @@ -46,16 +73,27 @@ DM::DM() : fd( -1 ) struct sockaddr_un sa; if (DMType == Unknown) { - if (!(dpy = ::getenv( "DISPLAY" ))) - DMType = NoDM; - else if ((ctl = ::getenv( "DM_CONTROL" ))) + if (!(dpy = ::getenv( "DISPLAY" ))) { + // Try to read TDM control file + if ((ctl = readcfg(KDE_CONFDIR "/tdm/tdmrc")) != TQString::null) { + DMType = NewTDM; + } + else { + DMType = NoDM; + } + } + else if ((ctl = ::getenv( "DM_CONTROL" )) != TQString::null) { DMType = NewTDM; - else if ((ctl = ::getenv( "XDM_MANAGED" )) && ctl[0] == '/') + } + else if (((ctl = ::getenv( "XDM_MANAGED" )) != TQString::null) && ctl[0] == '/') { DMType = OldTDM; - else if (::getenv( "GDMSESSION" )) + } + else if (::getenv( "GDMSESSION" )) { DMType = GDM; - else + } + else { DMType = NoDM; + } } switch (DMType) { default: @@ -76,12 +114,17 @@ DM::DM() : fd( -1 ) } } GDMAuthenticate(); - } else { - if ((ptr = const_cast(strchr( dpy, ':' )))) - ptr = strchr( ptr, '.' ); - snprintf( sa.sun_path, sizeof(sa.sun_path), - "%s/dmctl-%.*s/socket", - ctl, ptr ? int(ptr - dpy) : 512, dpy ); + } + else { + if (!dpy) { + snprintf( sa.sun_path, sizeof(sa.sun_path), "%s/dmctl/socket", ctl.ascii() ); + } + else { + if ((ptr = const_cast(strchr( dpy, ':' )))) { + ptr = strchr( ptr, '.' ); + } + snprintf( sa.sun_path, sizeof(sa.sun_path), "%s/dmctl-%.*s/socket", ctl.ascii(), ptr ? int(ptr - dpy) : 512, dpy ); + } if (::connect( fd, (struct sockaddr *)&sa, sizeof(sa) )) { ::close( fd ); fd = -1; @@ -100,8 +143,9 @@ DM::DM() : fd( -1 ) DM::~DM() { - if (fd >= 0) + if (fd >= 0) { close( fd ); + } } bool @@ -172,13 +216,15 @@ DM::exec( const char *cmd, TQCString &buf ) bool DM::canShutdown() { - if (DMType == OldTDM) - return strstr( ctl, ",maysd" ) != 0; + if (DMType == OldTDM) { + return strstr( ctl.ascii(), ",maysd" ) != 0; + } TQCString re; - if (DMType == GDM) + if (DMType == GDM) { return exec( "QUERY_LOGOUT_ACTION\n", re ) && re.find("HALT") >= 0; + } return exec( "caps\n", re ) && re.find( "\tshutdown" ) >= 0; } @@ -282,7 +328,7 @@ DM::numReserve() return 1; /* Bleh */ if (DMType == OldTDM) - return strstr( ctl, ",rsvd" ) ? 1 : -1; + return strstr( ctl.ascii(), ",rsvd" ) ? 1 : -1; TQCString re; int p; @@ -304,8 +350,9 @@ DM::startReserve() bool DM::localSessions( SessList &list ) { - if (DMType == OldTDM) + if (DMType == OldTDM) { return false; + } TQCString re; @@ -325,8 +372,9 @@ DM::localSessions( SessList &list ) list.append( se ); } } else { - if (!exec( "list\talllocal\n", re )) + if (!exec( "list\talllocal\n", re )) { return false; + } TQStringList sess = TQStringList::split( TQChar('\t'), re.data() + 3 ); for (TQStringList::ConstIterator it = sess.begin(); it != sess.end(); ++it) { TQStringList ts = TQStringList::split( TQChar(','), *it, true ); diff --git a/tdmlib/kgreet_classic.cpp b/tdmlib/kgreet_classic.cpp index 3d1cedc19..6aac4d96a 100644 --- a/tdmlib/kgreet_classic.cpp +++ b/tdmlib/kgreet_classic.cpp @@ -45,6 +45,15 @@ protected: static int echoMode; +TQString KClassicGreeter::passwordPrompt() { + if (func == Authenticate) { + return i18n("&Password:"); + } + else { + return i18n("Current &password:"); + } +} + KClassicGreeter::KClassicGreeter( KGreeterPluginHandler *_handler, KdmThemer *themer, TQWidget *parent, TQWidget *pred, @@ -60,7 +69,7 @@ KClassicGreeter::KClassicGreeter( KGreeterPluginHandler *_handler, running( false ) { KdmItem *user_entry = 0, *pw_entry = 0; - TQGridLayout *grid = 0; + grid = 0; int line = 0; layoutItem = 0; @@ -120,11 +129,7 @@ KClassicGreeter::KClassicGreeter( KGreeterPluginHandler *_handler, passwdEdit->adjustSize(); pw_entry->setWidget( passwdEdit ); } else { - passwdLabel = new TQLabel( passwdEdit, - func == Authenticate ? - i18n("&Password:") : - i18n("Current &password:"), - parent ); + passwdLabel = new TQLabel( passwdEdit, passwordPrompt(), parent ); grid->addWidget( passwdLabel, line, 0 ); grid->addWidget( passwdEdit, line++, 1 ); } @@ -217,6 +222,10 @@ KClassicGreeter::setUser( const TQString &user ) passwdEdit->selectAll(); } +void KClassicGreeter::lockUserEntry( const bool lock ) { + loginEdit->setEnabled(!lock); +} + void // virtual KClassicGreeter::setPassword( const TQString &pass ) { @@ -276,10 +285,24 @@ void // virtual KClassicGreeter::textPrompt( const char *prompt, bool echo, bool nonBlocking ) { pExp = exp; - if (echo) + if (echo) { exp = 0; - else if (!authTok) + } + else if (!authTok) { exp = 1; + if (passwdLabel) { + if (prompt && (prompt[0] != 0)) { + passwdLabel->setText(prompt); + } + else { + passwdLabel->setText(passwordPrompt()); + } + if (grid) { + grid->invalidate(); + grid->activate(); + } + } + } else { TQString pr( prompt ); if (pr.find( TQRegExp( "\\bpassword\\b", false ) ) >= 0) { @@ -294,7 +317,8 @@ KClassicGreeter::textPrompt( const char *prompt, bool echo, bool nonBlocking ) KGreeterPluginHandler::IsSecret ); return; } - } else { + } + else { handler->gplugMsgBox( TQMessageBox::Critical, i18n("Unrecognized prompt \"%1\"") .arg( prompt ) ); @@ -392,6 +416,15 @@ KClassicGreeter::succeeded() void // virtual KClassicGreeter::failed() { + if (passwdLabel) { + // reset password prompt + passwdLabel->setText(passwordPrompt()); + if (grid) { + grid->invalidate(); + grid->activate(); + } + } + // assert( running || timed_login ); setActive( false ); setActive2( false ); @@ -402,6 +435,15 @@ KClassicGreeter::failed() void // virtual KClassicGreeter::revive() { + if (passwdLabel) { + // reset password prompt + passwdLabel->setText(passwordPrompt()); + if (grid) { + grid->invalidate(); + grid->activate(); + } + } + // assert( !running ); setActive2( true ); if (authTok) { @@ -425,6 +467,15 @@ KClassicGreeter::revive() void // virtual KClassicGreeter::clear() { + if (passwdLabel) { + // reset password prompt + passwdLabel->setText(passwordPrompt()); + if (grid) { + grid->invalidate(); + grid->activate(); + } + } + // assert( !running && !passwd1Edit ); passwdEdit->erase(); if (loginEdit) { diff --git a/tdmlib/kgreet_classic.h b/tdmlib/kgreet_classic.h index 1f467a528..78bacf50d 100644 --- a/tdmlib/kgreet_classic.h +++ b/tdmlib/kgreet_classic.h @@ -50,6 +50,7 @@ class KClassicGreeter : public TQObject, public KGreeterPlugin { virtual void presetEntity( const TQString &entity, int field ); virtual TQString getEntity() const; virtual void setUser( const TQString &user ); + virtual void lockUserEntry( const bool lock ); virtual void setPassword( const TQString &pass ); virtual void setEnabled( bool on ); virtual bool textMessage( const char *message, bool error ); @@ -70,6 +71,7 @@ class KClassicGreeter : public TQObject, public KGreeterPlugin { void slotActivity(); private: + TQString passwordPrompt(); void setActive( bool enable ); void setActive2( bool enable ); void returnData(); @@ -81,6 +83,7 @@ class KClassicGreeter : public TQObject, public KGreeterPlugin { TQString fixedUser, curUser; Function func; Context ctx; + TQGridLayout* grid; int exp, pExp, has; bool running, authTok; }; diff --git a/tdmlib/kgreet_pam.cpp b/tdmlib/kgreet_pam.cpp index b16dfb440..97d19afde 100644 --- a/tdmlib/kgreet_pam.cpp +++ b/tdmlib/kgreet_pam.cpp @@ -263,6 +263,10 @@ KPamGreeter::setUser( const TQString &user ) } } +void KPamGreeter::lockUserEntry( const bool lock ) { + loginEdit->setEnabled(!lock); +} + void // virtual KPamGreeter::setPassword( const TQString &pass ) { diff --git a/tdmlib/kgreet_pam.h b/tdmlib/kgreet_pam.h index 03c404c1e..7772880a1 100644 --- a/tdmlib/kgreet_pam.h +++ b/tdmlib/kgreet_pam.h @@ -50,6 +50,7 @@ class KPamGreeter : public TQObject, public KGreeterPlugin { virtual void presetEntity( const TQString &entity, int field ); virtual TQString getEntity() const; virtual void setUser( const TQString &user ); + virtual void lockUserEntry( const bool lock ); virtual void setPassword( const TQString &pass ); virtual void setEnabled( bool on ); virtual bool textMessage( const char *message, bool error ); diff --git a/tdmlib/kgreet_winbind.cpp b/tdmlib/kgreet_winbind.cpp index aa7e39b18..53b992fa6 100644 --- a/tdmlib/kgreet_winbind.cpp +++ b/tdmlib/kgreet_winbind.cpp @@ -297,6 +297,10 @@ KWinbindGreeter::setUser( const TQString &user ) passwdEdit->selectAll(); } +void KWinbindGreeter::lockUserEntry( const bool lock ) { + loginEdit->setEnabled(!lock); +} + void // virtual KWinbindGreeter::setPassword( const TQString &pass ) { diff --git a/tdmlib/kgreet_winbind.h b/tdmlib/kgreet_winbind.h index 54f2653fc..8c41ca5d7 100644 --- a/tdmlib/kgreet_winbind.h +++ b/tdmlib/kgreet_winbind.h @@ -54,6 +54,7 @@ class KWinbindGreeter : public TQObject, public KGreeterPlugin { virtual void presetEntity( const TQString &entity, int field ); virtual TQString getEntity() const; virtual void setUser( const TQString &user ); + virtual void lockUserEntry( const bool lock ); virtual void setPassword( const TQString &pass ); virtual void setEnabled( bool on ); virtual bool textMessage( const char *message, bool error ); diff --git a/tdmlib/kgreeterplugin.h b/tdmlib/kgreeterplugin.h index 925828455..4604a6aac 100644 --- a/tdmlib/kgreeterplugin.h +++ b/tdmlib/kgreeterplugin.h @@ -151,6 +151,12 @@ public: */ virtual void setUser( const TQString &user ) = 0; + /** + * Lock or unlock editing of the username entry field + * @param lock true to lock, false to unlock + */ + virtual void lockUserEntry( const bool lock ) = 0; + /** * "Push" a password into the talker. * @param pass the password to set. @@ -183,7 +189,7 @@ public: /** * Prompt the user for data. Reply by calling handler->gplugReturnText(). - * @param propmt the prompt to display. It may be null, in which case + * @param prompt the prompt to display. It may be null, in which case * "Username"/"Password" should be shown and the replies should be tagged * with the respective Is* flag. * @param echo if true, a normal input widget can be used, otherwise one that