diff options
Diffstat (limited to 'kdmlib/kgreet_winbind.cpp')
-rw-r--r-- | kdmlib/kgreet_winbind.cpp | 671 |
1 files changed, 671 insertions, 0 deletions
diff --git a/kdmlib/kgreet_winbind.cpp b/kdmlib/kgreet_winbind.cpp new file mode 100644 index 000000000..eeef08b01 --- /dev/null +++ b/kdmlib/kgreet_winbind.cpp @@ -0,0 +1,671 @@ +/* + +Conversation widget for kdm greeter + +Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org> +Copyright (C) 2000-2004 Oswald Buddenhagen <ossi@kde.org> + + +This program 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#include "kgreet_winbind.h" +#include "themer/kdmthemer.h" +#include "themer/kdmitem.h" + +#include <klocale.h> +#include <kdebug.h> +#include <kcombobox.h> +#include <klineedit.h> +#include <kpassdlg.h> +#include <kuser.h> +#include <kprocio.h> + +#include <qregexp.h> +#include <qlayout.h> +#include <qlabel.h> + +#include <stdlib.h> + +class KDMPasswordEdit : public KPasswordEdit { +public: + KDMPasswordEdit( QWidget *parent ) : KPasswordEdit( parent, 0 ) {} + KDMPasswordEdit( KPasswordEdit::EchoModes echoMode, QWidget *parent ) : KPasswordEdit( echoMode, parent, 0 ) {} +protected: + virtual void contextMenuEvent( QContextMenuEvent * ) {} +}; + +static int echoMode; +static char separator; +static QStringList staticDomains; +static QString defaultDomain; + +static void +splitEntity( const QString &ent, QString &dom, QString &usr ) +{ + int pos = ent.find( separator ); + if (pos < 0) + dom = "<local>", usr = ent; + else + dom = ent.left( pos ), usr = ent.mid( pos + 1 ); +} + +KWinbindGreeter::KWinbindGreeter( KGreeterPluginHandler *_handler, + KdmThemer *themer, + QWidget *parent, QWidget *pred, + const QString &_fixedEntity, + Function _func, Context _ctx ) : + QObject(), + KGreeterPlugin( _handler ), + func( _func ), + ctx( _ctx ), + exp( -1 ), + pExp( -1 ), + running( false ) +{ + KdmItem *user_entry = 0, *pw_entry = 0, *domain_entry = 0; + QGridLayout *grid = 0; + + int line = 0; + layoutItem = 0; + + if (themer && + (!(user_entry = themer->findNode( "user-entry" )) || + !(pw_entry = themer->findNode( "pw-entry" )) || + !(domain_entry = themer->findNode( "domain-entry" )))) + themer = 0; + + if (!themer) + layoutItem = grid = new QGridLayout( 0, 0, 10 ); + + domainLabel = loginLabel = passwdLabel = passwd1Label = passwd2Label = 0; + domainCombo = 0; + loginEdit = 0; + passwdEdit = passwd1Edit = passwd2Edit = 0; + m_domainLister = 0; + if (ctx == ExUnlock || ctx == ExChangeTok) + splitEntity( KUser().loginName(), fixedDomain, fixedUser ); + else + splitEntity( _fixedEntity, fixedDomain, fixedUser ); + if (func != ChAuthTok) { + if (fixedUser.isEmpty()) { + domainCombo = new KComboBox( parent ); + connect( domainCombo, SIGNAL(activated( const QString & )), + SLOT(slotChangedDomain( const QString & )) ); + connect( domainCombo, SIGNAL(activated( const QString & )), + SLOT(slotLoginLostFocus()) ); + connect( domainCombo, SIGNAL(activated( const QString & )), + SLOT(slotActivity()) ); + // should handle loss of focus + loginEdit = new KLineEdit( parent ); + loginEdit->setContextMenuEnabled( false ); + + if (pred) { + parent->setTabOrder( pred, domainCombo ); + parent->setTabOrder( domainCombo, loginEdit ); + pred = loginEdit; + } + if (!grid) { + loginEdit->adjustSize(); + domainCombo->adjustSize(); + user_entry->setWidget( loginEdit ); + domain_entry->setWidget( domainCombo ); + } else { + domainLabel = new QLabel( domainCombo, i18n("&Domain:"), parent ); + loginLabel = new QLabel( loginEdit, i18n("&Username:"), parent ); + grid->addWidget( domainLabel, line, 0 ); + grid->addWidget( domainCombo, line++, 1 ); + grid->addWidget( loginLabel, line, 0 ); + grid->addWidget( loginEdit, line++, 1 ); + } + connect( loginEdit, SIGNAL(lostFocus()), SLOT(slotLoginLostFocus()) ); + connect( loginEdit, SIGNAL(lostFocus()), SLOT(slotActivity()) ); + connect( loginEdit, SIGNAL(textChanged( const QString & )), SLOT(slotActivity()) ); + connect( loginEdit, SIGNAL(selectionChanged()), SLOT(slotActivity()) ); + connect(&mDomainListTimer, SIGNAL(timeout()), SLOT(slotStartDomainList())); + domainCombo->insertStringList( staticDomains ); + QTimer::singleShot(0, this, SLOT(slotStartDomainList())); + } else if (ctx != Login && ctx != Shutdown && grid) { + domainLabel = new QLabel( i18n("Domain:"), parent ); + grid->addWidget( domainLabel, line, 0 ); + grid->addWidget( new QLabel( fixedDomain, parent ), line++, 1 ); + loginLabel = new QLabel( i18n("Username:"), parent ); + grid->addWidget( loginLabel, line, 0 ); + grid->addWidget( new QLabel( fixedUser, parent ), line++, 1 ); + } + if (echoMode == -1) + passwdEdit = new KDMPasswordEdit( parent ); + else + passwdEdit = new KDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, + parent ); + connect( passwdEdit, SIGNAL(textChanged( const QString & )), + SLOT(slotActivity()) ); + connect( passwdEdit, SIGNAL(lostFocus()), SLOT(slotActivity()) ); + + if (!grid) { + passwdEdit->adjustSize(); + pw_entry->setWidget( passwdEdit ); + } else { + passwdLabel = new QLabel( passwdEdit, + func == Authenticate ? + i18n("&Password:") : + i18n("Current &password:"), + parent ); + if (pred) { + parent->setTabOrder( pred, passwdEdit ); + pred = passwdEdit; + } + grid->addWidget( passwdLabel, line, 0 ); + grid->addWidget( passwdEdit, line++, 1 ); + } + + if (loginEdit) + loginEdit->setFocus(); + else + passwdEdit->setFocus(); + } + if (func != Authenticate) { + if (echoMode == -1) { + passwd1Edit = new KDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, parent ); + passwd2Edit = new KDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, parent ); + } else { + passwd1Edit = new KDMPasswordEdit( parent ); + passwd2Edit = new KDMPasswordEdit( parent ); + } + passwd1Label = new QLabel( passwd1Edit, i18n("&New password:"), parent ); + passwd2Label = new QLabel( passwd2Edit, i18n("Con&firm password:"), parent ); + if (pred) { + parent->setTabOrder( pred, passwd1Edit ); + parent->setTabOrder( passwd1Edit, passwd2Edit ); + } + if (grid) { + grid->addWidget( passwd1Label, line, 0 ); + grid->addWidget( passwd1Edit, line++, 1 ); + grid->addWidget( passwd2Label, line, 0 ); + grid->addWidget( passwd2Edit, line, 1 ); + } + if (!passwdEdit) + passwd1Edit->setFocus(); + } +} + +// virtual +KWinbindGreeter::~KWinbindGreeter() +{ + abort(); + if (!layoutItem) { + delete loginEdit; + delete passwdEdit; + delete domainCombo; + return; + } + QLayoutIterator it = static_cast<QLayout *>(layoutItem)->iterator(); + for (QLayoutItem *itm = it.current(); itm; itm = ++it) + delete itm->widget(); + delete layoutItem; + delete m_domainLister; +} + +void +KWinbindGreeter::slotChangedDomain( const QString &dom ) +{ + if (!loginEdit->completionObject()) + return; + QStringList users; + if (dom == "<local>") { + for (QStringList::ConstIterator it = allUsers.begin(); it != allUsers.end(); ++it) + if ((*it).find( separator ) < 0) + users << *it; + } else { + QString st( dom + separator ); + for (QStringList::ConstIterator it = allUsers.begin(); it != allUsers.end(); ++it) + if ((*it).startsWith( st )) + users << (*it).mid( st.length() ); + } + loginEdit->completionObject()->setItems( users ); +} + +void // virtual +KWinbindGreeter::loadUsers( const QStringList &users ) +{ + allUsers = users; + KCompletion *userNamesCompletion = new KCompletion; + loginEdit->setCompletionObject( userNamesCompletion ); + loginEdit->setAutoDeleteCompletionObject( true ); + loginEdit->setCompletionMode( KGlobalSettings::CompletionAuto ); + slotChangedDomain( defaultDomain ); +} + +void // virtual +KWinbindGreeter::presetEntity( const QString &entity, int field ) +{ + QString dom, usr; + splitEntity( entity, dom, usr ); + domainCombo->setCurrentItem( dom, true ); + slotChangedDomain( dom ); + loginEdit->setText( usr ); + if (field > 1) + passwdEdit->setFocus(); + else if (field == 1 || field == -1) { + if (field == -1) { + passwdEdit->setText( " " ); + passwdEdit->setEnabled( false ); + authTok = false; + } + loginEdit->setFocus(); + loginEdit->selectAll(); + } + curUser = entity; +} + +QString // virtual +KWinbindGreeter::getEntity() const +{ + QString dom, usr; + if (fixedUser.isEmpty()) + dom = domainCombo->currentText(), usr = loginEdit->text(); + else + dom = fixedDomain, usr = fixedUser; + return dom == "<local>" ? usr : dom + separator + usr; +} + +void // virtual +KWinbindGreeter::setUser( const QString &user ) +{ + // assert (fixedUser.isEmpty()); + curUser = user; + QString dom, usr; + splitEntity( user, dom, usr ); + domainCombo->setCurrentItem( dom, true ); + slotChangedDomain( dom ); + loginEdit->setText( usr ); + passwdEdit->setFocus(); + passwdEdit->selectAll(); +} + +void // virtual +KWinbindGreeter::setEnabled( bool enable ) +{ + // assert( !passwd1Label ); + // assert( func == Authenticate && ctx == Shutdown ); +// if (domainCombo) +// domainCombo->setEnabled( enable ); +// if (loginLabel) +// loginLabel->setEnabled( enable ); + passwdLabel->setEnabled( enable ); + setActive( enable ); + if (enable) + passwdEdit->setFocus(); +} + +void // private +KWinbindGreeter::returnData() +{ + switch (exp) { + case 0: + handler->gplugReturnText( getEntity().local8Bit(), + KGreeterPluginHandler::IsUser ); + break; + case 1: + handler->gplugReturnText( passwdEdit->password(), + KGreeterPluginHandler::IsPassword | + KGreeterPluginHandler::IsSecret ); + break; + case 2: + handler->gplugReturnText( passwd1Edit->password(), + KGreeterPluginHandler::IsSecret ); + break; + default: // case 3: + handler->gplugReturnText( passwd2Edit->password(), + KGreeterPluginHandler::IsNewPassword | + KGreeterPluginHandler::IsSecret ); + break; + } +} + +bool // virtual +KWinbindGreeter::textMessage( const char *text, bool err ) +{ + if (!err && + QString( text ).find( QRegExp( "^Changing password for [^ ]+$" ) ) >= 0) + return true; + return false; +} + +void // virtual +KWinbindGreeter::textPrompt( const char *prompt, bool echo, bool nonBlocking ) +{ + pExp = exp; + if (echo) + exp = 0; + else if (!authTok) + exp = 1; + else { + QString pr( prompt ); + if (pr.find( QRegExp( "\\b(old|current)\\b", false ) ) >= 0) { + handler->gplugReturnText( "", + KGreeterPluginHandler::IsOldPassword | + KGreeterPluginHandler::IsSecret ); + return; + } else if (pr.find( QRegExp( "\\b(re-?(enter|type)|again|confirm|repeat)\\b", + false ) ) >= 0) + exp = 3; + else if (pr.find( QRegExp( "\\bnew\\b", false ) ) >= 0) + exp = 2; + else { + handler->gplugMsgBox( QMessageBox::Critical, + i18n("Unrecognized prompt \"%1\"") + .arg( prompt ) ); + handler->gplugReturnText( 0, 0 ); + exp = -1; + return; + } + } + + if (pExp >= 0 && pExp >= exp) { + revive(); + has = -1; + } + + if (has >= exp || nonBlocking) + returnData(); +} + +bool // virtual +KWinbindGreeter::binaryPrompt( const char *, bool ) +{ + // this simply cannot happen ... :} + return true; +} + +void // virtual +KWinbindGreeter::start() +{ + authTok = !(passwdEdit && passwdEdit->isEnabled()); + exp = has = -1; + running = true; +} + +void // virtual +KWinbindGreeter::suspend() +{ +} + +void // virtual +KWinbindGreeter::resume() +{ +} + +void // virtual +KWinbindGreeter::next() +{ + // assert( running ); + if (domainCombo && domainCombo->hasFocus()) + loginEdit->setFocus(); + else if (loginEdit && loginEdit->hasFocus()) { + passwdEdit->setFocus(); // will cancel running login if necessary + has = 0; + } else if (passwdEdit && passwdEdit->hasFocus()) { + if (passwd1Edit) + passwd1Edit->setFocus(); + has = 1; + } else if (passwd1Edit) { + if (passwd1Edit->hasFocus()) { + passwd2Edit->setFocus(); + has = 1; // sic! + } else + has = 3; + } else + has = 1; + if (exp < 0) + handler->gplugStart(); + else if (has >= exp) + returnData(); +} + +void // virtual +KWinbindGreeter::abort() +{ + running = false; + if (exp >= 0) { + exp = -1; + handler->gplugReturnText( 0, 0 ); + } +} + +void // virtual +KWinbindGreeter::succeeded() +{ + // assert( running || timed_login ); + if (!authTok) { + setActive( false ); + if (passwd1Edit) { + authTok = true; + return; + } + } else + setActive2( false ); + exp = -1; + running = false; +} + +void // virtual +KWinbindGreeter::failed() +{ + // assert( running || timed_login ); + setActive( false ); + setActive2( false ); + exp = -1; + running = false; +} + +void // virtual +KWinbindGreeter::revive() +{ + // assert( !running ); + setActive2( true ); + if (authTok) { + passwd1Edit->erase(); + passwd2Edit->erase(); + passwd1Edit->setFocus(); + } else { + passwdEdit->erase(); + if (loginEdit && loginEdit->isEnabled()) + passwdEdit->setEnabled( true ); + else { + setActive( true ); + if (loginEdit && loginEdit->text().isEmpty()) + loginEdit->setFocus(); + else + passwdEdit->setFocus(); + } + } +} + +void // virtual +KWinbindGreeter::clear() +{ + // assert( !running && !passwd1Edit ); + passwdEdit->erase(); + if (loginEdit) { + domainCombo->setCurrentItem( defaultDomain ); + slotChangedDomain( defaultDomain ); + loginEdit->clear(); + loginEdit->setFocus(); + curUser = QString::null; + } else + passwdEdit->setFocus(); +} + + +// private + +void +KWinbindGreeter::setActive( bool enable ) +{ + if (domainCombo) + domainCombo->setEnabled( enable ); + if (loginEdit) + loginEdit->setEnabled( enable ); + if (passwdEdit) + passwdEdit->setEnabled( enable ); +} + +void +KWinbindGreeter::setActive2( bool enable ) +{ + if (passwd1Edit) { + passwd1Edit->setEnabled( enable ); + passwd2Edit->setEnabled( enable ); + } +} + +void +KWinbindGreeter::slotLoginLostFocus() +{ + if (!running) + return; + QString ent( getEntity() ); + if (exp > 0) { + if (curUser == ent) + return; + exp = -1; + handler->gplugReturnText( 0, 0 ); + } + curUser = ent; + handler->gplugSetUser( curUser ); +} + +void +KWinbindGreeter::slotActivity() +{ + if (running) + handler->gplugActivity(); +} + +void +KWinbindGreeter::slotStartDomainList() +{ + mDomainListTimer.stop(); + mDomainListing.clear(); + + m_domainLister = new KProcIO; + connect(m_domainLister, SIGNAL(readReady(KProcIO*)), SLOT(slotReadDomainList())); + connect(m_domainLister, SIGNAL(processExited(KProcess*)), SLOT(slotEndDomainList())); + + (*m_domainLister) << "wbinfo" << "--own-domain" << "--trusted-domains"; + m_domainLister->setComm (KProcess::Stdout); + m_domainLister->start(); +} + +void +KWinbindGreeter::slotReadDomainList() +{ + QString line; + + while ( m_domainLister->readln( line ) != -1 ) { + mDomainListing.append(line); + } +} + +void +KWinbindGreeter::slotEndDomainList() +{ + delete m_domainLister; + m_domainLister = 0; + + QStringList domainList; + domainList = staticDomains; + + for (QStringList::const_iterator it = mDomainListing.begin(); + it != mDomainListing.end(); ++it) { + + if (!domainList.contains(*it)) + domainList.append(*it); + } + + QString current = domainCombo->currentText(); + + for (int i = 0; i < domainList.count(); ++i) { + if (i < domainCombo->count()) + domainCombo->changeItem(domainList[i], i); + else + domainCombo->insertItem(domainList[i], i); + } + + while (domainCombo->count() > domainList.count()) + domainCombo->removeItem(domainCombo->count()-1); + + domainCombo->setCurrentItem( current ); + + if (domainCombo->currentText() != current) + domainCombo->setCurrentItem( defaultDomain ); + + mDomainListTimer.start(5 * 1000); +} + +// factory + +static bool init( const QString &, + QVariant (*getConf)( void *, const char *, const QVariant & ), + void *ctx ) +{ + echoMode = getConf( ctx, "EchoMode", QVariant( -1 ) ).toInt(); + staticDomains = QStringList::split( ':', getConf( ctx, "winbind.Domains", QVariant( "" ) ).toString() ); + if (!staticDomains.contains("<local>")) + staticDomains << "<local>"; + + defaultDomain = getConf( ctx, "winbind.DefaultDomain", QVariant( staticDomains.first() ) ).toString(); + QString sepstr = getConf( ctx, "winbind.Separator", QVariant( QString::null ) ).toString(); + if (sepstr.isNull()) { + FILE *sepfile = popen( "wbinfo --separator 2>/dev/null", "r" ); + if (sepfile) { + QTextIStream( sepfile ) >> sepstr; + if (pclose( sepfile )) + sepstr = "\\"; + } else + sepstr = "\\"; + } + separator = sepstr[0].latin1(); + KGlobal::locale()->insertCatalogue( "kgreet_winbind" ); + return true; +} + +static void done( void ) +{ + KGlobal::locale()->removeCatalogue( "kgreet_winbind" ); + // avoid static deletion problems ... hopefully + staticDomains.clear(); + defaultDomain = QString::null; +} + +static KGreeterPlugin * +create( KGreeterPluginHandler *handler, KdmThemer *themer, + QWidget *parent, QWidget *predecessor, + const QString &fixedEntity, + KGreeterPlugin::Function func, + KGreeterPlugin::Context ctx ) +{ + return new KWinbindGreeter( handler, themer, parent, predecessor, fixedEntity, func, ctx ); +} + +KDE_EXPORT kgreeterplugin_info kgreeterplugin_info = { + I18N_NOOP("Winbind / Samba"), "classic", + kgreeterplugin_info::Local | kgreeterplugin_info::Fielded | kgreeterplugin_info::Presettable, + init, done, create +}; + +#include "kgreet_winbind.moc" |