Index: kdm/backend/client.c =================================================================== --- kdm/backend/client.c.orig +++ kdm/backend/client.c @@ -547,6 +547,9 @@ Verify( GConvFunc gconv, int rootok ) } else psrv = PAMService; pdata.usecur = TRUE; + } else if (!strcmp( curtype, "pam" )) { + psrv = PAMService; + pdata.usecur = FALSE; } else { sprintf( psrvb, "%.31s-%.31s", PAMService, curtype ); psrv = psrvb; @@ -616,7 +619,7 @@ Verify( GConvFunc gconv, int rootok ) free( msg ); V_RET_FAIL( 0 ); } - } else if (!strcmp( curtype, "generic" )) { + } else if (!strcmp( curtype, "generic" ) || !strcmp(curtype, "pam")) { if (!gconv( GCONV_USER, 0 )) return 0; for (curret = 0;;) { Index: kdm/kfrontend/themer/kdmlabel.h =================================================================== --- kdm/kfrontend/themer/kdmlabel.h.orig +++ kdm/kfrontend/themer/kdmlabel.h @@ -50,6 +50,7 @@ protected: // handle switching between normal / active / prelight configurations virtual void statusChanged(); +public: struct LabelStruct { QString text; bool isTimer; Index: kdmlib/kgreet_pam.cpp =================================================================== --- /dev/null +++ kdmlib/kgreet_pam.cpp @@ -0,0 +1,668 @@ +/* + +Conversation widget for kdm greeter + +Copyright (C) 2008 Dirk Mueller + +based on classic kdm greeter: + + Copyright (C) 1997, 1998, 2000 Steffen Hansen + Copyright (C) 2000-2003 Oswald Buddenhagen + + +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_pam.h" +#include "themer/kdmthemer.h" +#include "themer/kdmlabel.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +//#define PAM_GREETER_DEBUG + +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 FILE* log; +static void debug(const char* fmt, ...) +{ + va_list lst; + va_start(lst, fmt); + +#ifdef PAM_GREETER_DEBUG +#if 0 + vfprintf(log, fmt, lst); + fflush(log); +#else + char buf[6000]; + sprintf(buf, "*** %s\n", fmt); + vsyslog(LOG_WARNING, buf, lst); +#endif +#endif + va_end(lst); +} + +static KPasswordEdit::EchoModes echoMode; + +KPamGreeter::KPamGreeter( KGreeterPluginHandler *_handler, + KdmThemer *themer, + QWidget *parent, QWidget *pred, + const QString &_fixedEntity, + Function _func, Context _ctx ) : + QObject(), + KGreeterPlugin( _handler ), + fixedUser( _fixedEntity ), + func( _func ), + ctx( _ctx ), + exp( -1 ), + pExp( -1 ), + running( false ) +{ + ctx = Login; + + debug("KPamGreeter constructed\n"); + + m_parentWidget = parent; + + KdmItem *user_entry = 0, *pw_entry = 0; + int line = 0; + + layoutItem = 0; + + if (themer && + (!(user_entry = themer->findNode( "user-entry" )) || + !(pw_entry = themer->findNode( "pw-entry" )))) + themer = 0; + + m_themer = themer; + + if (!themer) + layoutItem = new QGridLayout( 0, 0, 10 ); + + loginLabel = 0; + authLabel.clear(); + authEdit.clear(); + loginLabel = 0; + loginEdit = 0; + if (ctx == ExUnlock || ctx == ExChangeTok) + fixedUser = KUser().loginName(); + if (func != ChAuthTok) { + debug("func != ChAuthTok\n"); + debug("fixedUser: *%s*\n", fixedUser.latin1()); + + if (fixedUser.isEmpty()) { + loginEdit = new KLineEdit( parent ); + loginEdit->setContextMenuEnabled( false ); + 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()) ); + if (pred) { + parent->setTabOrder( pred, loginEdit ); + pred = loginEdit; + } + if (!getLayoutItem()) { + loginEdit->adjustSize(); + user_entry->setWidget( loginEdit ); + } else { + loginLabel = new QLabel( loginEdit, i18n("Username:"), parent ); + getLayoutItem()->addWidget( loginLabel, line, 0 ); + getLayoutItem()->addWidget( loginEdit, line++, 1 ); + } + } else if (ctx != Login && ctx != Shutdown && getLayoutItem()) { + loginLabel = new QLabel( i18n("Username:"), parent ); + getLayoutItem()->addWidget( loginLabel, line, 0 ); + getLayoutItem()->addWidget( new QLabel( fixedUser, parent ), line++, 1 ); + } +#if 0 + if (echoMode == -1) + passwdEdit = new KDMPasswordEdit( parent ); + else + passwdEdit = new KDMPasswordEdit( echoMode, + parent ); + connect( passwdEdit, SIGNAL(textChanged( const QString & )), + SLOT(slotActivity()) ); + connect( passwdEdit, SIGNAL(lostFocus()), SLOT(slotActivity()) ); + if (pred) { + parent->setTabOrder( pred, passwdEdit ); + pred = passwdEdit; + } + if (!getLayoutItem()) { + passwdEdit->adjustSize(); + pw_entry->setWidget( passwdEdit ); + } else { + passwdLabel = new QLabel( passwdEdit, + func == Authenticate ? + i18n("hello &Password:") : + i18n("Current &password:"), + parent ); + getLayoutItem()->addWidget( passwdLabel, line, 0 ); + getLayoutItem()->addWidget( passwdEdit, line++, 1 ); + } +#endif + if (loginEdit) + loginEdit->setFocus(); + } + if (func != Authenticate) { + if (echoMode == -1) { + authEdit << new KDMPasswordEdit( echoMode, parent ); + authEdit << new KDMPasswordEdit( echoMode, parent ); + } else { + authEdit << new KDMPasswordEdit( parent ); + authEdit << new KDMPasswordEdit( parent ); + } + authLabel << new QLabel( authEdit[0], i18n("&New password:"), parent ); + authLabel << new QLabel( authEdit[1], i18n("Con&firm password:"), parent ); + if (pred) { + parent->setTabOrder( pred, authEdit[0] ); + parent->setTabOrder( authEdit[0], authEdit[1] ); + } + if (getLayoutItem()) { + getLayoutItem()->addWidget( authLabel[0], line, 0 ); + getLayoutItem()->addWidget( authEdit[0], line++, 1 ); + getLayoutItem()->addWidget( authLabel[1], line, 0 ); + getLayoutItem()->addWidget( authEdit[1], line, 1 ); + } + if (authEdit.size() >= 2) + authEdit[1]->setFocus(); + } +} + +// virtual +KPamGreeter::~KPamGreeter() +{ + debug("KPamGreeter::~KPamGreeter"); + abort(); + if (!layoutItem) { + delete loginEdit; + return; + } + QLayoutIterator it = static_cast(layoutItem)->iterator(); + for (QLayoutItem *itm = it.current(); itm; itm = ++it) + delete itm->widget(); + delete layoutItem; + debug("destructor finished, good bye"); +} + +void // virtual +KPamGreeter::loadUsers( const QStringList &users ) +{ + KCompletion *userNamesCompletion = new KCompletion; + userNamesCompletion->setItems( users ); + loginEdit->setCompletionObject( userNamesCompletion ); + loginEdit->setAutoDeleteCompletionObject( true ); + loginEdit->setCompletionMode( KGlobalSettings::CompletionAuto ); +} + +void // virtual +KPamGreeter::presetEntity( const QString &entity, int field ) +{ + debug("presetEntity(%s,%d) called!\n", entity.latin1(), field); + loginEdit->setText( entity ); + if (field == 1 && authEdit.size() >= 1) + authEdit[0]->setFocus(); + else { + loginEdit->setFocus(); + loginEdit->selectAll(); + if (field == -1 && authEdit.size() >= 1) { + authEdit[0]->setText( " " ); + authEdit[0]->setEnabled( false ); + authTok = false; + } + } + curUser = entity; +} + +QString // virtual +KPamGreeter::getEntity() const +{ + return fixedUser.isEmpty() ? loginEdit->text() : fixedUser; +} + +void // virtual +KPamGreeter::setUser( const QString &user ) +{ + // assert( fixedUser.isEmpty() ); + curUser = user; + loginEdit->setText( user ); + if (authEdit.size() >= 1) { + authEdit[0]->setFocus(); + authEdit[0]->selectAll(); + } +} + +void // virtual +KPamGreeter::setEnabled(bool enable) +{ + // assert( !passwd1Label ); + // assert( func == Authenticate && ctx == Shutdown ); +// if (loginLabel) +// loginLabel->setEnabled( enable ); + authEdit[0]->setEnabled( enable ); + setActive( enable ); + if (enable) + authEdit[0]->setFocus(); + } + +void // private +KPamGreeter::returnData() +{ + debug("*************** returnData called with exp %d\n", exp); + + + switch (exp) { + case 0: + handler->gplugReturnText( (loginEdit ? loginEdit->text() : + fixedUser).local8Bit(), + KGreeterPluginHandler::IsUser ); + break; + case 1: + handler->gplugReturnText( authEdit[0]->password(), + KGreeterPluginHandler::IsPassword | + KGreeterPluginHandler::IsSecret ); + break; + case 2: + handler->gplugReturnText( authEdit[1]->password(), + KGreeterPluginHandler::IsSecret ); + break; + default: // case 3: + handler->gplugReturnText( authEdit[2]->password(), + KGreeterPluginHandler::IsNewPassword | + KGreeterPluginHandler::IsSecret ); + break; + } +} + +bool // virtual +KPamGreeter::textMessage( const char *text, bool err ) +{ + debug(" ************** textMessage(%s, %d)\n", text, err); + + if (!authEdit.size()) + return false; + + if (getLayoutItem()) { + QLabel* label = new QLabel(QString::fromUtf8(text), m_parentWidget); + getLayoutItem()->addWidget(label, state+1, 0, 0); + } + + return true; +} + +void // virtual +KPamGreeter::textPrompt( const char *prompt, bool echo, bool nonBlocking ) +{ + debug("textPrompt called with prompt %s echo %d nonBlocking %d", prompt, echo, nonBlocking); + debug("state is %d, authEdit.size is %d\n", state, authEdit.size()); + + if (state == 0 && echo) { + if (loginLabel) + loginLabel->setText(QString::fromUtf8(prompt)); + else if (m_themer) { + KdmLabel *kdmlabel = static_cast(m_themer->findNode("user-label")); + if (kdmlabel) { + //userLabel->setText(QString::fromUtf8(prompt)); + kdmlabel->label.text = QString::fromUtf8(prompt); + QTimer::singleShot(0, kdmlabel, SLOT(update())); + } + } + } + else if (state >= authEdit.size()) { + if (getLayoutItem()) { + QLabel* label = new QLabel(QString::fromUtf8(prompt), m_parentWidget); + getLayoutItem()->addWidget(label, state+1, 0, 0); + debug("added label widget to layout"); + } + else if (m_themer) { + debug("themer found!"); + KdmItem *pw_label = 0; + + KdmLabel *kdmlabel = static_cast(m_themer->findNode("pw-label")); + if (kdmlabel) { + //userLabel->setText(QString::fromUtf8(prompt)); + QString str = QString::fromUtf8(prompt); + kdmlabel->label.text = str; + QTimer::singleShot(0, kdmlabel, SLOT(update())); + } + } + + KDMPasswordEdit* passwdEdit; + + if (echoMode == -1) + passwdEdit = new KDMPasswordEdit( m_parentWidget ); + else + passwdEdit = new KDMPasswordEdit( echoMode, m_parentWidget); + connect( passwdEdit, SIGNAL(textChanged( const QString & )), + SLOT(slotActivity()) ); + connect( passwdEdit, SIGNAL(lostFocus()), SLOT(slotActivity()) ); + authEdit << passwdEdit; + +#if 1 + for(QValueList::iterator it = authEdit.begin(); + it != authEdit.end(); + ++it) { + if ((*it)->isEnabled() && (*it)->text().isEmpty()) { + (*it)->setFocus(); + break; + } + } +#endif + if (getLayoutItem()) + getLayoutItem()->addWidget(passwdEdit, state+1, 1, 0); + + if (m_themer) { + debug("themer found!"); + KdmItem *pw_entry = 0; + + pw_entry = m_themer->findNode("pw-entry"); + + if (pw_entry && passwdEdit) + pw_entry->setWidget(passwdEdit); + + if (0) { + //userLabel->setText(QString::fromUtf8(prompt)); + //kdmlabel->label.text = QString::fromUtf8(prompt); + //QTimer::singleShot(0, kdmlabel, SLOT(update())); + } + } + else + debug("no themer found!"); + } + ++state; + pExp = exp; + + exp = authEdit.size(); + debug("state %d exp: %d, has %d\n", state, exp, has); + + if (has >= exp || nonBlocking) + returnData(); +} + +bool // virtual +KPamGreeter::binaryPrompt( const char *, bool ) +{ + // this simply cannot happen ... :} + return true; +} + +void // virtual +KPamGreeter::start() +{ + debug("******* start() called\n"); + + while(authEdit.begin() != authEdit.end()) { + KPasswordEdit* item = *authEdit.remove(authEdit.begin()); + delete item; + } + + while(authLabel.begin() != authLabel.end()) { + QLabel* item = *authLabel.remove(authLabel.begin()); + delete item; + } + + authTok = !(authEdit.size() >= 2 && authEdit[1]->isEnabled()); + exp = has = -1; + state = 0; + running = true; + handler->gplugStart(); +} + +void // virtual +KPamGreeter::suspend() +{ +} + +void // virtual +KPamGreeter::resume() +{ +} + +void // virtual +KPamGreeter::next() +{ + debug("********* next() called state %d\n", state); + + if (state == 0 && running && handler) { + debug(" **** returned text!\n"); + handler->gplugReturnText( (loginEdit ? loginEdit->text() : + fixedUser).local8Bit(), + KGreeterPluginHandler::IsUser ); + setActive(false); + } + + has = 0; + + for(QValueList::iterator it = authEdit.begin(); + it != authEdit.end(); + ++it) { + + has++; + if ((*it)->hasFocus()) { + ++it; + if (it != authEdit.end()) + (*it)->setFocus(); + break; + } + if (it == authEdit.end()) + has = -1; + } + + debug(" has %d and exp %d\n", has, exp); + +#if 0 + // assert( running ); + 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(); +#endif + if (has >= exp) + returnData(); +} + +void // virtual +KPamGreeter::abort() +{ + debug("***** abort() called\n"); + + running = false; + if (exp >= 0) { + exp = -1; + handler->gplugReturnText( 0, 0 ); + } +} + +void // virtual +KPamGreeter::succeeded() +{ + debug("**** succeeded() called\n"); + + // assert( running || timed_login ); + if (!authTok) + setActive( false ); + else + setAllActive( false ); + exp = -1; + running = false; +} + +void // virtual +KPamGreeter::failed() +{ + // assert( running || timed_login ); + setActive( false ); + setAllActive( false ); + exp = -1; + running = false; +} + +#include +void // virtual +KPamGreeter::revive() +{ + // assert( !running ); + setAllActive( true ); + +#if 1 + if (authEdit.size() < 1) + return; +#endif + + assert(authEdit.size() >= 1); + if (authTok) { + authEdit[0]->erase(); + if(authEdit.size() >= 2) + authEdit[1]->erase(); + authEdit[0]->setFocus(); + } else { + authEdit[0]->erase(); + if (loginEdit && loginEdit->isEnabled()) + authEdit[0]->setEnabled( true ); + else { + setActive( true ); + if (loginEdit && loginEdit->text().isEmpty()) + loginEdit->setFocus(); + else + authEdit[0]->setFocus(); + } + } +} + +void // virtual +KPamGreeter::clear() +{ + // assert( !running && !passwd1Edit ); + authEdit[0]->erase(); + if (loginEdit) { + loginEdit->clear(); + loginEdit->setFocus(); + curUser = QString::null; + } else + authEdit[0]->setFocus(); +} + + +// private + +void +KPamGreeter::setActive( bool enable ) +{ + if (loginEdit) + loginEdit->setEnabled( enable ); +} + +void +KPamGreeter::setAllActive( bool enable ) +{ + for(QValueList::iterator it = authEdit.begin(); + it != authEdit.end(); + ++it) + (*it)->setEnabled( enable ); +} + +void +KPamGreeter::slotLoginLostFocus() +{ + if (!running) + return; + if (exp > 0) { + if (curUser == loginEdit->text()) + return; + exp = -1; + handler->gplugReturnText( 0, 0 ); + } + curUser = loginEdit->text(); + debug("curUser is %s", curUser.latin1()); + handler->gplugSetUser( curUser ); +} + +void +KPamGreeter::slotActivity() +{ + debug("slotActivity"); + + if (running) + handler->gplugActivity(); +} + +// factory + +static bool init( const QString &, + QVariant (*getConf)( void *, const char *, const QVariant & ), + void *ctx ) +{ + echoMode = (KPasswordEdit::EchoModes) getConf( ctx, "EchoMode", QVariant( -1 ) ).toInt(); + KGlobal::locale()->insertCatalogue( "kgreet_pam" ); + return true; +} + +static void done( void ) +{ + KGlobal::locale()->removeCatalogue( "kgreet_pam" ); + if (log && log != stderr) + fclose(log); + log = 0; +} + +static KGreeterPlugin * +create( KGreeterPluginHandler *handler, KdmThemer *themer, + QWidget *parent, QWidget *predecessor, + const QString &fixedEntity, + KGreeterPlugin::Function func, + KGreeterPlugin::Context ctx ) +{ + return new KPamGreeter( handler, themer, parent, predecessor, fixedEntity, func, ctx ); +} + +KDE_EXPORT kgreeterplugin_info kgreeterplugin_info = { + I18N_NOOP("Pam conversation plugin"), "pam", + kgreeterplugin_info::Local | kgreeterplugin_info::Presettable, + init, done, create +}; + +#include "kgreet_pam.moc" Index: kdmlib/kgreet_pam.h =================================================================== --- /dev/null +++ kdmlib/kgreet_pam.h @@ -0,0 +1,93 @@ +/* + +Conversation widget for kdm greeter + +Copyright (C) 2008 Dirk Mueller + + +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. + +*/ + + +#ifndef KGREET_CLASSIC_H +#define KGREET_CLASSIC_H + +#include "kgreeterplugin.h" + +#include +#include + +class KLineEdit; +class KPasswordEdit; +class KSimpleConfig; +class QGridLayout; +class QLabel; + +class KPamGreeter : public QObject, public KGreeterPlugin { + Q_OBJECT + + public: + KPamGreeter( KGreeterPluginHandler *handler, + KdmThemer *themer, + QWidget *parent, QWidget *predecessor, + const QString &fixedEntitiy, + Function func, Context ctx ); + ~KPamGreeter(); + virtual void loadUsers( const QStringList &users ); + virtual void presetEntity( const QString &entity, int field ); + virtual QString getEntity() const; + virtual void setUser( const QString &user ); + virtual void setEnabled( bool on ); + virtual bool textMessage( const char *message, bool error ); + virtual void textPrompt( const char *prompt, bool echo, bool nonBlocking ); + virtual bool binaryPrompt( const char *prompt, bool nonBlocking ); + virtual void start(); + virtual void suspend(); + virtual void resume(); + virtual void next(); + virtual void abort(); + virtual void succeeded(); + virtual void failed(); + virtual void revive(); + virtual void clear(); + + QGridLayout *getLayoutItem() const { return static_cast(layoutItem); } + + public slots: + void slotLoginLostFocus(); + void slotActivity(); + + private: + void setActive( bool enable ); + void setAllActive( bool enable ); + void returnData(); + + QLabel *loginLabel; + QValueList authLabel; + KLineEdit *loginEdit; + QWidget* m_parentWidget; + QValueList authEdit; + KSimpleConfig *stsFile; + KdmThemer *m_themer; + QString fixedUser, curUser; + Function func; + Context ctx; + int exp, pExp, has; + unsigned state; + bool running, authTok; +}; + +#endif /* KGREET_CLASSIC_H */ Index: kdmlib/Makefile.am =================================================================== --- kdmlib/Makefile.am.orig +++ kdmlib/Makefile.am @@ -1,11 +1,15 @@ AM_CPPFLAGS = -I$(top_srcdir)/kdm/kfrontend $(all_includes) -kde_module_LTLIBRARIES = kgreet_classic.la kgreet_winbind.la +kde_module_LTLIBRARIES = kgreet_classic.la kgreet_pam.la kgreet_winbind.la kgreet_classic_la_SOURCES = kgreet_classic.cpp kgreet_classic_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries) kgreet_classic_la_LIBADD = $(LIB_KDEUI) +kgreet_pam_la_SOURCES = kgreet_pam.cpp +kgreet_pam_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries) +kgreet_pam_la_LIBADD = $(LIB_KDEUI) + kgreet_winbind_la_SOURCES = kgreet_winbind.cpp kgreet_winbind_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries) kgreet_winbind_la_LIBADD = $(LIB_KDEUI) Index: kcheckpass/checkpass_pam.c =================================================================== --- kcheckpass/checkpass_pam.c.orig +++ kcheckpass/checkpass_pam.c @@ -140,13 +140,16 @@ AuthReturn Authenticate(const char *call openlog("kcheckpass", LOG_PID, LOG_AUTH); PAM_data.conv = conv; - if (strcmp(method, "classic")) { - sprintf(pservb, "%.31s-%.31s", caller, method); - pam_service = pservb; - } else { + if (!strcmp(method, "classic")) { PAM_data.classic = 1; pam_service = caller; } + else if (!strcmp(method, "pam")) { + pam_service = caller; + } else { + sprintf(pservb, "%.31s-%.31s", caller, method); + pam_service = pservb; + } pam_error = pam_start(pam_service, user, &PAM_conversation, &pamh); if (pam_error != PAM_SUCCESS) return AuthError;