You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1219 lines
28 KiB
1219 lines
28 KiB
/*
|
|
|
|
Shell for kdm conversation plugins
|
|
|
|
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 <config.h>
|
|
|
|
#include "kgverify.h"
|
|
#include "kdmconfig.h"
|
|
#include "kdm_greet.h"
|
|
|
|
#include "themer/kdmthemer.h"
|
|
#include "themer/kdmitem.h"
|
|
|
|
#include <kapplication.h>
|
|
#include <klocale.h>
|
|
#include <klibloader.h>
|
|
#include <kseparator.h>
|
|
#include <kstdguiitem.h>
|
|
#include <kpushbutton.h>
|
|
|
|
#include <tqregexp.h>
|
|
#include <tqpopupmenu.h>
|
|
#include <tqlayout.h>
|
|
#include <tqfile.h>
|
|
#include <tqlabel.h>
|
|
|
|
#include <pwd.h>
|
|
#include <sys/types.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#include <X11/Xlib.h> // for updateLockStatus()
|
|
#include <fixx11h.h> // ... and make eventFilter() work again
|
|
|
|
#define FULL_GREET_TO 40 // normal inactivity timeout
|
|
#define TIMED_GREET_TO 20 // inactivity timeout when persisting timed login
|
|
#define MIN_TIMED_TO 5 // minimal timed login delay
|
|
#define DEAD_TIMED_TO 2 // <enter> dead time after re-activating timed login
|
|
#define SECONDS 1000 // reduce to 100 to speed up testing
|
|
|
|
void KGVerifyHandler::verifyClear()
|
|
{
|
|
}
|
|
|
|
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 )
|
|
: 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 )
|
|
{
|
|
connect( &timer, TQT_SIGNAL(timeout()), TQT_SLOT(slotTimeout()) );
|
|
connect( kapp, TQT_SIGNAL(activity()), TQT_SLOT(slotActivity()) );
|
|
|
|
_parent->installEventFilter( this );
|
|
}
|
|
|
|
KGVerify::~KGVerify()
|
|
{
|
|
Debug( "delete %s\n", pName.data() );
|
|
delete greet;
|
|
}
|
|
|
|
TQPopupMenu *
|
|
KGVerify::getPlugMenu()
|
|
{
|
|
// assert( !cont );
|
|
if (!plugMenu) {
|
|
uint np = pluginList.count();
|
|
if (np > 1) {
|
|
plugMenu = new TQPopupMenu( parent );
|
|
connect( plugMenu, TQT_SIGNAL(activated( int )),
|
|
TQT_SLOT(slotPluginSelected( int )) );
|
|
for (uint i = 0; i < np; i++)
|
|
plugMenu->insertItem( i18n(greetPlugins[pluginList[i]].info->name), pluginList[i] );
|
|
}
|
|
}
|
|
return plugMenu;
|
|
}
|
|
|
|
bool // public
|
|
KGVerify::entitiesLocal() const
|
|
{
|
|
return greetPlugins[pluginList[curPlugin]].info->flags & kgreeterplugin_info::Local;
|
|
}
|
|
|
|
bool // public
|
|
KGVerify::entitiesFielded() const
|
|
{
|
|
return greetPlugins[pluginList[curPlugin]].info->flags & kgreeterplugin_info::Fielded;
|
|
}
|
|
|
|
bool // public
|
|
KGVerify::entityPresettable() const
|
|
{
|
|
return greetPlugins[pluginList[curPlugin]].info->flags & kgreeterplugin_info::Presettable;
|
|
}
|
|
|
|
bool // public
|
|
KGVerify::isClassic() const
|
|
{
|
|
return !strcmp( greetPlugins[pluginList[curPlugin]].info->method, "classic" );
|
|
}
|
|
|
|
TQString // public
|
|
KGVerify::pluginName() const
|
|
{
|
|
TQString name( greetPlugins[pluginList[curPlugin]].library->fileName() );
|
|
uint st = name.findRev( '/' ) + 1;
|
|
uint en = name.find( '.', st );
|
|
if (en - st > 7 && TQConstString( name.tqunicode() + st, 7 ).string() == "kgreet_")
|
|
st += 7;
|
|
return name.mid( st, en - st );
|
|
}
|
|
|
|
static void
|
|
showWidgets( TQLayoutItem *li )
|
|
{
|
|
TQWidget *w;
|
|
TQLayout *l;
|
|
|
|
if ((w = li->widget()))
|
|
w->show();
|
|
else if ((l = li->tqlayout())) {
|
|
TQLayoutIterator it = l->iterator();
|
|
for (TQLayoutItem *itm = it.current(); itm; itm = ++it)
|
|
showWidgets( itm );
|
|
}
|
|
}
|
|
|
|
void // public
|
|
KGVerify::selectPlugin( int id )
|
|
{
|
|
if (pluginList.isEmpty()) {
|
|
MsgBox( errorbox, i18n("No greeter widget plugin loaded. Check the configuration.") );
|
|
::exit( EX_UNMANAGE_DPY );
|
|
}
|
|
curPlugin = id;
|
|
if (plugMenu)
|
|
plugMenu->setItemChecked( id, true );
|
|
pName = ("greet_" + pluginName()).latin1();
|
|
Debug( "new %s\n", pName.data() );
|
|
greet = greetPlugins[pluginList[id]].info->create( this, themer, parent, predecessor, fixedEntity, func, ctx );
|
|
timeable = _autoLoginDelay && entityPresettable() && isClassic();
|
|
}
|
|
|
|
void // public
|
|
KGVerify::loadUsers( const TQStringList &users )
|
|
{
|
|
Debug( "%s->loadUsers(...)\n", pName.data() );
|
|
greet->loadUsers( users );
|
|
}
|
|
|
|
void // public
|
|
KGVerify::presetEntity( const TQString &entity, int field )
|
|
{
|
|
presEnt = entity;
|
|
presFld = field;
|
|
}
|
|
|
|
bool // private
|
|
KGVerify::applyPreset()
|
|
{
|
|
if (!presEnt.isEmpty()) {
|
|
Debug( "%s->presetEntity(%\"s, %d)\n", pName.data(),
|
|
presEnt.latin1(), presFld );
|
|
greet->presetEntity( presEnt, presFld );
|
|
if (entitiesLocal()) {
|
|
curUser = presEnt;
|
|
handler->verifySetUser( presEnt );
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool // private
|
|
KGVerify::scheduleAutoLogin( bool initial )
|
|
{
|
|
if (timeable) {
|
|
Debug( "%s->presetEntity(%\"s, -1)\n", pName.data(),
|
|
_autoLoginUser.latin1(), -1 );
|
|
greet->presetEntity( _autoLoginUser, -1 );
|
|
curUser = _autoLoginUser;
|
|
handler->verifySetUser( _autoLoginUser );
|
|
timer.start( 1000 );
|
|
if (initial) {
|
|
timedLeft = _autoLoginDelay;
|
|
deadTicks = 0;
|
|
} else {
|
|
timedLeft = QMAX( _autoLoginDelay - TIMED_GREET_TO, MIN_TIMED_TO );
|
|
deadTicks = DEAD_TIMED_TO;
|
|
}
|
|
updateStatus();
|
|
running = false;
|
|
isClear = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void // private
|
|
KGVerify::performAutoLogin()
|
|
{
|
|
// timer.stop();
|
|
GSendInt( G_AutoLogin );
|
|
handleVerify();
|
|
}
|
|
|
|
TQString // public
|
|
KGVerify::getEntity() const
|
|
{
|
|
Debug( "%s->getEntity()\n", pName.data() );
|
|
TQString ent = greet->getEntity();
|
|
Debug( " entity: %s\n", ent.latin1() );
|
|
return ent;
|
|
}
|
|
|
|
void
|
|
KGVerify::setUser( const TQString &user )
|
|
{
|
|
// assert( fixedEntity.isEmpty() );
|
|
curUser = user;
|
|
Debug( "%s->setUser(%\"s)\n", pName.data(), user.latin1() );
|
|
greet->setUser( user );
|
|
gplugActivity();
|
|
}
|
|
|
|
void
|
|
KGVerify::setPassword( const TQString &pass )
|
|
{
|
|
greet->setPassword( pass );
|
|
gplugActivity();
|
|
}
|
|
|
|
void
|
|
KGVerify::start()
|
|
{
|
|
authTok = (func == KGreeterPlugin::ChAuthTok);
|
|
cont = false;
|
|
if (func == KGreeterPlugin::Authenticate && ctx == KGreeterPlugin::Login) {
|
|
if (scheduleAutoLogin( true )) {
|
|
if (!_autoLoginAgain)
|
|
_autoLoginDelay = 0, timeable = false;
|
|
return;
|
|
} else
|
|
applyPreset();
|
|
}
|
|
running = true;
|
|
Debug( "%s->start()\n", pName.data() );
|
|
greet->start();
|
|
if (!(func == KGreeterPlugin::Authenticate ||
|
|
ctx == KGreeterPlugin::ChangeTok ||
|
|
ctx == KGreeterPlugin::ExChangeTok))
|
|
{
|
|
cont = true;
|
|
handleVerify();
|
|
}
|
|
}
|
|
|
|
void
|
|
KGVerify::abort()
|
|
{
|
|
Debug( "%s->abort()\n", pName.data() );
|
|
greet->abort();
|
|
running = false;
|
|
}
|
|
|
|
void
|
|
KGVerify::suspend()
|
|
{
|
|
// assert( !cont );
|
|
if (running) {
|
|
Debug( "%s->abort()\n", pName.data() );
|
|
greet->abort();
|
|
}
|
|
suspended = true;
|
|
updateStatus();
|
|
timer.suspend();
|
|
}
|
|
|
|
void
|
|
KGVerify::resume()
|
|
{
|
|
timer.resume();
|
|
suspended = false;
|
|
updateLockStatus();
|
|
if (running) {
|
|
Debug( "%s->start()\n", pName.data() );
|
|
greet->start();
|
|
} else if (delayed) {
|
|
delayed = false;
|
|
running = true;
|
|
Debug( "%s->start()\n", pName.data() );
|
|
greet->start();
|
|
}
|
|
}
|
|
|
|
void // not a slot - called manually by greeter
|
|
KGVerify::accept()
|
|
{
|
|
Debug( "%s->next()\n", pName.data() );
|
|
greet->next();
|
|
}
|
|
|
|
void // private
|
|
KGVerify::doReject( bool initial )
|
|
{
|
|
// assert( !cont );
|
|
if (running) {
|
|
Debug( "%s->abort()\n", pName.data() );
|
|
greet->abort();
|
|
}
|
|
handler->verifyClear();
|
|
Debug( "%s->clear()\n", pName.data() );
|
|
greet->clear();
|
|
curUser = TQString::null;
|
|
if (!scheduleAutoLogin( initial )) {
|
|
isClear = !(isClear && applyPreset());
|
|
if (running) {
|
|
Debug( "%s->start()\n", pName.data() );
|
|
greet->start();
|
|
}
|
|
if (!failed)
|
|
timer.stop();
|
|
}
|
|
}
|
|
|
|
void // not a slot - called manually by greeter
|
|
KGVerify::reject()
|
|
{
|
|
doReject( true );
|
|
}
|
|
|
|
void
|
|
KGVerify::setEnabled( bool on )
|
|
{
|
|
Debug( "%s->setEnabled(%s)\n", pName.data(), on ? "true" : "false" );
|
|
greet->setEnabled( on );
|
|
enabled = on;
|
|
updateStatus();
|
|
}
|
|
|
|
void // private
|
|
KGVerify::slotTimeout()
|
|
{
|
|
if (failed) {
|
|
failed = false;
|
|
updateStatus();
|
|
Debug( "%s->revive()\n", pName.data() );
|
|
greet->revive();
|
|
handler->verifyRetry();
|
|
if (suspended)
|
|
delayed = true;
|
|
else {
|
|
running = true;
|
|
Debug( "%s->start()\n", pName.data() );
|
|
greet->start();
|
|
slotActivity();
|
|
gplugActivity();
|
|
if (cont)
|
|
handleVerify();
|
|
}
|
|
} else if (timedLeft) {
|
|
deadTicks--;
|
|
if (!--timedLeft)
|
|
performAutoLogin();
|
|
else
|
|
timer.start( 1000 );
|
|
updateStatus();
|
|
} else {
|
|
// assert( ctx == Login );
|
|
isClear = true;
|
|
doReject( false );
|
|
}
|
|
}
|
|
|
|
void
|
|
KGVerify::slotActivity()
|
|
{
|
|
if (timedLeft) {
|
|
Debug( "%s->revive()\n", pName.data() );
|
|
greet->revive();
|
|
Debug( "%s->start()\n", pName.data() );
|
|
greet->start();
|
|
running = true;
|
|
timedLeft = 0;
|
|
updateStatus();
|
|
timer.start( TIMED_GREET_TO * SECONDS );
|
|
} else if (timeable)
|
|
timer.start( TIMED_GREET_TO * SECONDS );
|
|
}
|
|
|
|
|
|
void // private static
|
|
KGVerify::VMsgBox( TQWidget *parent, const TQString &user,
|
|
TQMessageBox::Icon type, const TQString &mesg )
|
|
{
|
|
FDialog::box( parent, type, user.isEmpty() ?
|
|
mesg : i18n("Authenticating %1...\n\n").arg( user ) + mesg );
|
|
}
|
|
|
|
static const char *msgs[]= {
|
|
I18N_NOOP( "You are required to change your password immediately (password aged)." ),
|
|
I18N_NOOP( "You are required to change your password immediately (root enforced)." ),
|
|
I18N_NOOP( "You are not allowed to login at the moment." ),
|
|
I18N_NOOP( "Home folder not available." ),
|
|
I18N_NOOP( "Logins are not allowed at the moment.\nTry again later." ),
|
|
I18N_NOOP( "Your login shell is not listed in /etc/shells." ),
|
|
I18N_NOOP( "Root logins are not allowed." ),
|
|
I18N_NOOP( "Your account has expired; please contact your system administrator." )
|
|
};
|
|
|
|
void // private static
|
|
KGVerify::VErrBox( TQWidget *parent, const TQString &user, const char *msg )
|
|
{
|
|
TQMessageBox::Icon icon;
|
|
TQString mesg;
|
|
|
|
if (!msg) {
|
|
mesg = i18n("A critical error occurred.\n"
|
|
"Please look at KDM's logfile(s) for more information\n"
|
|
"or contact your system administrator.");
|
|
icon = errorbox;
|
|
} else {
|
|
mesg = TQString::fromLocal8Bit( msg );
|
|
TQString mesg1 = mesg + '.';
|
|
for (uint i = 0; i < as(msgs); i++)
|
|
if (mesg1 == msgs[i]) {
|
|
mesg = i18n(msgs[i]);
|
|
break;
|
|
}
|
|
icon = sorrybox;
|
|
}
|
|
VMsgBox( parent, user, icon, mesg );
|
|
}
|
|
|
|
void // private static
|
|
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();
|
|
mesg = expire ?
|
|
i18n("Your account expires tomorrow.",
|
|
"Your account expires in %n days.", expire) :
|
|
i18n("Your account expires today.");
|
|
} else {
|
|
rx.setPattern( "^Warning: your password will expire in (\\d+) day" );
|
|
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 );
|
|
}
|
|
|
|
bool // public static
|
|
KGVerify::handleFailVerify( TQWidget *parent )
|
|
{
|
|
Debug( "handleFailVerify ...\n" );
|
|
char *msg = GRecvStr();
|
|
TQString user = TQString::fromLocal8Bit( msg );
|
|
free( msg );
|
|
|
|
for (;;) {
|
|
int ret = GRecvInt();
|
|
|
|
// non-terminal status
|
|
switch (ret) {
|
|
/* case V_PUT_USER: cannot happen - we are in "classic" mode */
|
|
/* case V_PRE_OK: cannot happen - not in ChTok dialog */
|
|
/* case V_CHTOK: cannot happen - called by non-interactive verify */
|
|
case V_CHTOK_AUTH:
|
|
Debug( " V_CHTOK_AUTH\n" );
|
|
{
|
|
TQStringList pgs( _pluginsLogin );
|
|
pgs += _pluginsShutdown;
|
|
TQStringList::ConstIterator it;
|
|
for (it = pgs.begin(); it != pgs.end(); ++it)
|
|
if (*it == "classic" || *it == "modern") {
|
|
pgs = *it;
|
|
goto gotit;
|
|
} else if (*it == "generic") {
|
|
pgs = "modern";
|
|
goto gotit;
|
|
}
|
|
pgs = "classic";
|
|
gotit:
|
|
KGChTok chtok( parent, user, init( pgs ), 0,
|
|
KGreeterPlugin::AuthChAuthTok,
|
|
KGreeterPlugin::Login );
|
|
return chtok.exec();
|
|
}
|
|
case V_MSG_ERR:
|
|
Debug( " V_MSG_ERR\n" );
|
|
msg = GRecvStr();
|
|
Debug( " message %\"s\n", msg );
|
|
VErrBox( parent, user, msg );
|
|
if (msg)
|
|
free( msg );
|
|
continue;
|
|
case V_MSG_INFO:
|
|
Debug( " V_MSG_INFO\n" );
|
|
msg = GRecvStr();
|
|
Debug( " message %\"s\n", msg );
|
|
VInfoBox( parent, user, msg );
|
|
free( msg );
|
|
continue;
|
|
}
|
|
|
|
// terminal status
|
|
switch (ret) {
|
|
case V_OK:
|
|
Debug( " V_OK\n" );
|
|
return true;
|
|
case V_AUTH:
|
|
Debug( " V_AUTH\n" );
|
|
VMsgBox( parent, user, sorrybox, i18n("Authentication failed") );
|
|
return false;
|
|
case V_FAIL:
|
|
Debug( " V_FAIL\n" );
|
|
return false;
|
|
default:
|
|
LogPanic( "Unknown V_xxx code %d from core\n", ret );
|
|
}
|
|
}
|
|
}
|
|
|
|
void // private
|
|
KGVerify::handleVerify()
|
|
{
|
|
TQString user;
|
|
|
|
Debug( "handleVerify ...\n" );
|
|
for (;;) {
|
|
char *msg;
|
|
int ret, echo, ndelay;
|
|
KGreeterPlugin::Function nfunc;
|
|
|
|
ret = GRecvInt();
|
|
|
|
// requests
|
|
coreLock = 1;
|
|
switch (ret) {
|
|
case V_GET_TEXT:
|
|
Debug( " V_GET_TEXT\n" );
|
|
msg = GRecvStr();
|
|
Debug( " prompt %\"s\n", msg );
|
|
echo = GRecvInt();
|
|
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 );
|
|
return;
|
|
case V_GET_BINARY:
|
|
Debug( " V_GET_BINARY\n" );
|
|
msg = GRecvArr( &ret );
|
|
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 );
|
|
return;
|
|
}
|
|
|
|
// non-terminal status
|
|
coreLock = 2;
|
|
switch (ret) {
|
|
case V_PUT_USER:
|
|
Debug( " V_PUT_USER\n" );
|
|
msg = GRecvStr();
|
|
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() );
|
|
greet->setUser( curUser );
|
|
handler->verifySetUser( curUser );
|
|
if (msg)
|
|
free( msg );
|
|
continue;
|
|
case V_PRE_OK: // this is only for func == AuthChAuthTok
|
|
Debug( " V_PRE_OK\n" );
|
|
// With the "classic" method, the wrong user simply cannot be
|
|
// authenticated, even with the generic plugin. Other methods
|
|
// could do so, but this applies only to ctx == ChangeTok, which
|
|
// is not implemented yet.
|
|
authTok = true;
|
|
cont = true;
|
|
Debug( "%s->succeeded()\n", pName.data() );
|
|
greet->succeeded();
|
|
continue;
|
|
case V_CHTOK_AUTH:
|
|
Debug( " V_CHTOK_AUTH\n" );
|
|
nfunc = KGreeterPlugin::AuthChAuthTok;
|
|
user = curUser;
|
|
goto dchtok;
|
|
case V_CHTOK:
|
|
Debug( " V_CHTOK\n" );
|
|
nfunc = KGreeterPlugin::ChAuthTok;
|
|
user = TQString::null;
|
|
dchtok:
|
|
{
|
|
timer.stop();
|
|
Debug( "%s->succeeded()\n", pName.data() );
|
|
greet->succeeded();
|
|
KGChTok chtok( parent, user, pluginList, curPlugin, nfunc, KGreeterPlugin::Login );
|
|
if (!chtok.exec())
|
|
goto retry;
|
|
handler->verifyOk();
|
|
return;
|
|
}
|
|
case V_MSG_ERR:
|
|
Debug( " V_MSG_ERR\n" );
|
|
msg = GRecvStr();
|
|
Debug( " %s->textMessage(%\"s, true)\n", pName.data(), msg );
|
|
if (!greet->textMessage( msg, true )) {
|
|
Debug( " message passed\n" );
|
|
VErrBox( parent, user, msg );
|
|
} else
|
|
Debug( " message swallowed\n" );
|
|
if (msg)
|
|
free( msg );
|
|
continue;
|
|
case V_MSG_INFO:
|
|
Debug( " V_MSG_INFO\n" );
|
|
msg = GRecvStr();
|
|
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 );
|
|
continue;
|
|
}
|
|
|
|
// terminal status
|
|
coreLock = 0;
|
|
running = false;
|
|
timer.stop();
|
|
|
|
if (ret == V_OK) {
|
|
Debug( " V_OK\n" );
|
|
if (!fixedEntity.isEmpty()) {
|
|
Debug( " %s->getEntity()\n", pName.data() );
|
|
TQString ent = greet->getEntity();
|
|
Debug( " entity %\"s\n", ent.latin1() );
|
|
if (ent != fixedEntity) {
|
|
Debug( "%s->failed()\n", pName.data() );
|
|
greet->failed();
|
|
MsgBox( sorrybox,
|
|
i18n("Authenticated user (%1) does not match requested user (%2).\n")
|
|
.arg( ent ).arg( fixedEntity ) );
|
|
goto retry;
|
|
}
|
|
}
|
|
Debug( "%s->succeeded()\n", pName.data() );
|
|
greet->succeeded();
|
|
handler->verifyOk();
|
|
return;
|
|
}
|
|
|
|
Debug( "%s->failed()\n", pName.data() );
|
|
greet->failed();
|
|
|
|
if (ret == V_AUTH) {
|
|
Debug( " V_AUTH\n" );
|
|
failed = true;
|
|
updateStatus();
|
|
handler->verifyFailed();
|
|
timer.start( 1500 + kapp->random()/(RAND_MAX/1000) );
|
|
return;
|
|
}
|
|
if (ret != V_FAIL)
|
|
LogPanic( "Unknown V_xxx code %d from core\n", ret );
|
|
Debug( " V_FAIL\n" );
|
|
retry:
|
|
Debug( "%s->revive()\n", pName.data() );
|
|
greet->revive();
|
|
running = true;
|
|
Debug( "%s->start()\n", pName.data() );
|
|
greet->start();
|
|
if (!cont)
|
|
return;
|
|
user = TQString::null;
|
|
}
|
|
}
|
|
|
|
void
|
|
KGVerify::gplugReturnText( const char *text, int tag )
|
|
{
|
|
Debug( "%s: gplugReturnText(%\"s, %d)\n", pName.data(),
|
|
tag & V_IS_SECRET ? "<masked>" : text, tag );
|
|
GSendStr( text );
|
|
if (text) {
|
|
GSendInt( tag );
|
|
handleVerify();
|
|
} else
|
|
coreLock = 0;
|
|
}
|
|
|
|
void
|
|
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 );
|
|
handleVerify();
|
|
} else {
|
|
Debug( "%s: gplugReturnBinary(NULL)\n", pName.data() );
|
|
GSendArr( 0, 0 );
|
|
coreLock = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
KGVerify::gplugSetUser( const TQString &user )
|
|
{
|
|
Debug( "%s: gplugSetUser(%\"s)\n", pName.data(), user.latin1() );
|
|
curUser = user;
|
|
handler->verifySetUser( user );
|
|
}
|
|
|
|
void
|
|
KGVerify::gplugStart()
|
|
{
|
|
// XXX handle func != Authenticate
|
|
Debug( "%s: gplugStart()\n", pName.data() );
|
|
GSendInt( ctx == KGreeterPlugin::Shutdown ? G_VerifyRootOK : G_Verify );
|
|
GSendStr( greetPlugins[pluginList[curPlugin]].info->method );
|
|
handleVerify();
|
|
}
|
|
|
|
void
|
|
KGVerify::gplugActivity()
|
|
{
|
|
Debug( "%s: gplugActivity()\n", pName.data() );
|
|
if (func == KGreeterPlugin::Authenticate &&
|
|
ctx == KGreeterPlugin::Login)
|
|
{
|
|
isClear = false;
|
|
if (!timeable)
|
|
timer.start( FULL_GREET_TO * SECONDS );
|
|
}
|
|
}
|
|
|
|
void
|
|
KGVerify::gplugMsgBox( TQMessageBox::Icon type, const TQString &text )
|
|
{
|
|
Debug( "%s: gplugMsgBox(%d, %\"s)\n", pName.data(), type, text.latin1() );
|
|
MsgBox( type, text );
|
|
}
|
|
|
|
bool
|
|
KGVerify::eventFilter( TQObject *o, TQEvent *e )
|
|
{
|
|
switch (e->type()) {
|
|
case TQEvent::KeyPress:
|
|
if (timedLeft) {
|
|
TQKeyEvent *ke = (TQKeyEvent *)e;
|
|
if (ke->key() == Key_Return || ke->key() == Key_Enter) {
|
|
if (deadTicks <= 0) {
|
|
timedLeft = 0;
|
|
performAutoLogin();
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
/* fall through */
|
|
case TQEvent::KeyRelease:
|
|
updateLockStatus();
|
|
/* fall through */
|
|
default:
|
|
break;
|
|
}
|
|
return inherited::eventFilter( o, e );
|
|
}
|
|
|
|
void
|
|
KGVerify::updateLockStatus()
|
|
{
|
|
unsigned int lmask;
|
|
Window dummy1, dummy2;
|
|
int dummy3, dummy4, dummy5, dummy6;
|
|
XQueryPointer( qt_xdisplay(), DefaultRootWindow( qt_xdisplay() ),
|
|
&dummy1, &dummy2, &dummy3, &dummy4, &dummy5, &dummy6,
|
|
&lmask );
|
|
capsLocked = lmask & LockMask;
|
|
updateStatus();
|
|
}
|
|
|
|
void
|
|
KGVerify::MsgBox( TQMessageBox::Icon typ, const TQString &msg )
|
|
{
|
|
timer.suspend();
|
|
FDialog::box( parent, typ, msg );
|
|
timer.resume();
|
|
}
|
|
|
|
|
|
TQVariant // public static
|
|
KGVerify::getConf( void *, const char *key, const TQVariant &dflt )
|
|
{
|
|
if (!qstrcmp( key, "EchoMode" ))
|
|
return TQVariant( _echoMode );
|
|
else {
|
|
TQString fkey = TQString::tqfromLatin1( key ) + '=';
|
|
for (TQStringList::ConstIterator it = _pluginOptions.begin();
|
|
it != _pluginOptions.end(); ++it)
|
|
if ((*it).startsWith( fkey ))
|
|
return (*it).mid( fkey.length() );
|
|
return dflt;
|
|
}
|
|
}
|
|
|
|
TQValueVector<GreeterPluginHandle> KGVerify::greetPlugins;
|
|
|
|
PluginList
|
|
KGVerify::init( const TQStringList &plugins )
|
|
{
|
|
PluginList pluginList;
|
|
|
|
for (TQStringList::ConstIterator it = plugins.begin(); it != plugins.end(); ++it) {
|
|
GreeterPluginHandle plugin;
|
|
TQString path = KLibLoader::self()->findLibrary(
|
|
((*it)[0] == '/' ? *it : "kgreet_" + *it ).latin1() );
|
|
if (path.isEmpty()) {
|
|
LogError( "GreeterPlugin %s does not exist\n", (*it).latin1() );
|
|
continue;
|
|
}
|
|
uint i, np = greetPlugins.count();
|
|
for (i = 0; i < np; i++)
|
|
if (greetPlugins[i].library->fileName() == path)
|
|
goto next;
|
|
if (!(plugin.library = KLibLoader::self()->library( path.latin1() ))) {
|
|
LogError( "Cannot load GreeterPlugin %s (%s)\n", (*it).latin1(), path.latin1() );
|
|
continue;
|
|
}
|
|
if (!plugin.library->hasSymbol( "kgreeterplugin_info" )) {
|
|
LogError( "GreeterPlugin %s (%s) is no valid greet widget plugin\n",
|
|
(*it).latin1(), path.latin1() );
|
|
plugin.library->unload();
|
|
continue;
|
|
}
|
|
plugin.info = (kgreeterplugin_info*)plugin.library->symbol( "kgreeterplugin_info" );
|
|
if (!plugin.info->init( TQString::null, getConf, 0 )) {
|
|
LogError( "GreeterPlugin %s (%s) refuses to serve\n",
|
|
(*it).latin1(), path.latin1() );
|
|
plugin.library->unload();
|
|
continue;
|
|
}
|
|
Debug( "GreeterPlugin %s (%s) loaded\n", (*it).latin1(), plugin.info->name );
|
|
greetPlugins.append( plugin );
|
|
next:
|
|
pluginList.append( i );
|
|
}
|
|
return pluginList;
|
|
}
|
|
|
|
void
|
|
KGVerify::done()
|
|
{
|
|
for (uint i = 0; i < greetPlugins.count(); i++) {
|
|
if (greetPlugins[i].info->done)
|
|
greetPlugins[i].info->done();
|
|
greetPlugins[i].library->unload();
|
|
}
|
|
}
|
|
|
|
|
|
KGStdVerify::KGStdVerify( KGVerifyHandler *_handler, TQWidget *_parent,
|
|
TQWidget *_predecessor, const TQString &_fixedUser,
|
|
const PluginList &_pluginList,
|
|
KGreeterPlugin::Function _func,
|
|
KGreeterPlugin::Context _ctx )
|
|
: inherited( _handler, 0, _parent, _predecessor, _fixedUser,
|
|
_pluginList, _func, _ctx )
|
|
, failedLabelState( 0 )
|
|
{
|
|
grid = new TQGridLayout;
|
|
grid->tqsetAlignment( AlignCenter );
|
|
|
|
failedLabel = new TQLabel( parent );
|
|
failedLabel->setFont( _failFont );
|
|
grid->addWidget( failedLabel, 1, 0, Qt::AlignCenter );
|
|
|
|
updateLockStatus();
|
|
}
|
|
|
|
KGStdVerify::~KGStdVerify()
|
|
{
|
|
grid->removeItem( greet->getLayoutItem() );
|
|
}
|
|
|
|
void // public
|
|
KGStdVerify::selectPlugin( int id )
|
|
{
|
|
inherited::selectPlugin( id );
|
|
grid->addItem( greet->getLayoutItem(), 0, 0 );
|
|
showWidgets( greet->getLayoutItem() );
|
|
}
|
|
|
|
void // private slot
|
|
KGStdVerify::slotPluginSelected( int id )
|
|
{
|
|
if (failed)
|
|
return;
|
|
if (id != curPlugin) {
|
|
plugMenu->setItemChecked( curPlugin, false );
|
|
parent->tqsetUpdatesEnabled( false );
|
|
grid->removeItem( greet->getLayoutItem() );
|
|
Debug( "delete %s\n", pName.data() );
|
|
delete greet;
|
|
selectPlugin( id );
|
|
handler->verifyPluginChanged( id );
|
|
if (running)
|
|
start();
|
|
parent->tqsetUpdatesEnabled( true );
|
|
}
|
|
}
|
|
|
|
void
|
|
KGStdVerify::updateStatus()
|
|
{
|
|
int nfls;
|
|
|
|
if (!enabled)
|
|
nfls = 1;
|
|
else if (failed)
|
|
nfls = 2;
|
|
else if (timedLeft)
|
|
nfls = -timedLeft;
|
|
else if (!suspended && capsLocked)
|
|
nfls = 3;
|
|
else
|
|
nfls = 1;
|
|
|
|
if (failedLabelState != nfls) {
|
|
failedLabelState = nfls;
|
|
if (nfls < 0) {
|
|
failedLabel->setPaletteForegroundColor( Qt::black );
|
|
failedLabel->setText( i18n( "Automatic login in 1 second...",
|
|
"Automatic login in %n seconds...",
|
|
timedLeft ) );
|
|
} else {
|
|
switch (nfls) {
|
|
default:
|
|
failedLabel->clear();
|
|
break;
|
|
case 3:
|
|
failedLabel->setPaletteForegroundColor( Qt::red );
|
|
failedLabel->setText( i18n("Warning: Caps Lock on") );
|
|
break;
|
|
case 2:
|
|
failedLabel->setPaletteForegroundColor( Qt::black );
|
|
failedLabel->setText( authTok ?
|
|
i18n("Change failed") :
|
|
fixedEntity.isEmpty() ?
|
|
i18n("Login failed") :
|
|
i18n("Authentication failed") );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
KGThemedVerify::KGThemedVerify( KGVerifyHandler *_handler,
|
|
KdmThemer *_themer,
|
|
TQWidget *_parent, TQWidget *_predecessor,
|
|
const TQString &_fixedUser,
|
|
const PluginList &_pluginList,
|
|
KGreeterPlugin::Function _func,
|
|
KGreeterPlugin::Context _ctx )
|
|
: inherited( _handler, _themer, _parent, _predecessor, _fixedUser,
|
|
_pluginList, _func, _ctx )
|
|
{
|
|
updateLockStatus();
|
|
}
|
|
|
|
KGThemedVerify::~KGThemedVerify()
|
|
{
|
|
}
|
|
|
|
void // public
|
|
KGThemedVerify::selectPlugin( int id )
|
|
{
|
|
inherited::selectPlugin( id );
|
|
TQLayoutItem *l;
|
|
KdmItem *n;
|
|
if (themer && (l = greet->getLayoutItem())) {
|
|
if (!(n = themer->findNode( "talker" )))
|
|
MsgBox( errorbox,
|
|
i18n("Theme not usable with authentication method '%1'.")
|
|
.arg( i18n(greetPlugins[pluginList[id]].info->name) ) );
|
|
else {
|
|
n->setLayoutItem( l );
|
|
showWidgets( l );
|
|
}
|
|
}
|
|
if (themer)
|
|
themer->updateGeometry( true );
|
|
}
|
|
|
|
void // private slot
|
|
KGThemedVerify::slotPluginSelected( int id )
|
|
{
|
|
if (failed)
|
|
return;
|
|
if (id != curPlugin) {
|
|
plugMenu->setItemChecked( curPlugin, false );
|
|
Debug( "delete %s\n", pName.data() );
|
|
delete greet;
|
|
selectPlugin( id );
|
|
handler->verifyPluginChanged( id );
|
|
if (running)
|
|
start();
|
|
}
|
|
}
|
|
|
|
void
|
|
KGThemedVerify::updateStatus()
|
|
{
|
|
handler->updateStatus( enabled && failed,
|
|
enabled && !suspended && capsLocked,
|
|
timedLeft );
|
|
}
|
|
|
|
|
|
KGChTok::KGChTok( TQWidget *_parent, const TQString &user,
|
|
const PluginList &pluginList, int curPlugin,
|
|
KGreeterPlugin::Function func,
|
|
KGreeterPlugin::Context ctx )
|
|
: inherited( _parent )
|
|
, verify( 0 )
|
|
{
|
|
TQSizePolicy fp( TQSizePolicy::Fixed, TQSizePolicy::Fixed );
|
|
okButton = new KPushButton( KStdGuiItem::ok(), this );
|
|
okButton->tqsetSizePolicy( fp );
|
|
okButton->setDefault( true );
|
|
cancelButton = new KPushButton( KStdGuiItem::cancel(), this );
|
|
cancelButton->tqsetSizePolicy( fp );
|
|
|
|
verify = new KGStdVerify( this, this, cancelButton, user, pluginList, func, ctx );
|
|
verify->selectPlugin( curPlugin );
|
|
|
|
TQVBoxLayout *box = new TQVBoxLayout( this, 10 );
|
|
|
|
box->addWidget( new TQLabel( i18n("Changing authentication token"), this ), 0, AlignHCenter );
|
|
|
|
box->addLayout( verify->getLayout() );
|
|
|
|
box->addWidget( new KSeparator( KSeparator::HLine, this ) );
|
|
|
|
TQHBoxLayout *hlay = new TQHBoxLayout( box );
|
|
hlay->addStretch( 1 );
|
|
hlay->addWidget( okButton );
|
|
hlay->addStretch( 1 );
|
|
hlay->addWidget( cancelButton );
|
|
hlay->addStretch( 1 );
|
|
|
|
connect( okButton, TQT_SIGNAL(clicked()), TQT_SLOT(accept()) );
|
|
connect( cancelButton, TQT_SIGNAL(clicked()), TQT_SLOT(reject()) );
|
|
|
|
TQTimer::singleShot( 0, verify, TQT_SLOT(start()) );
|
|
}
|
|
|
|
KGChTok::~KGChTok()
|
|
{
|
|
hide();
|
|
delete verify;
|
|
}
|
|
|
|
void
|
|
KGChTok::accept()
|
|
{
|
|
verify->accept();
|
|
}
|
|
|
|
void
|
|
KGChTok::verifyPluginChanged( int )
|
|
{
|
|
// cannot happen
|
|
}
|
|
|
|
void
|
|
KGChTok::verifyOk()
|
|
{
|
|
inherited::accept();
|
|
}
|
|
|
|
void
|
|
KGChTok::verifyFailed()
|
|
{
|
|
okButton->setEnabled( false );
|
|
cancelButton->setEnabled( false );
|
|
}
|
|
|
|
void
|
|
KGChTok::verifyRetry()
|
|
{
|
|
okButton->setEnabled( true );
|
|
cancelButton->setEnabled( true );
|
|
}
|
|
|
|
void
|
|
KGChTok::verifySetUser( const TQString & )
|
|
{
|
|
// cannot happen
|
|
}
|
|
|
|
|
|
////// helper class, nuke when qtimer supports suspend()/resume()
|
|
|
|
QXTimer::QXTimer()
|
|
: inherited( 0 )
|
|
, left( -1 )
|
|
{
|
|
connect( &timer, TQT_SIGNAL(timeout()), TQT_SLOT(slotTimeout()) );
|
|
}
|
|
|
|
void
|
|
QXTimer::start( int msec )
|
|
{
|
|
left = msec;
|
|
timer.start( left, true );
|
|
gettimeofday( &stv, 0 );
|
|
}
|
|
|
|
void
|
|
QXTimer::stop()
|
|
{
|
|
timer.stop();
|
|
left = -1;
|
|
}
|
|
|
|
void
|
|
QXTimer::suspend()
|
|
{
|
|
if (timer.isActive()) {
|
|
timer.stop();
|
|
struct timeval tv;
|
|
gettimeofday( &tv, 0 );
|
|
left -= (tv.tv_sec - stv.tv_sec) * 1000 + (tv.tv_usec - stv.tv_usec) / 1000;
|
|
if (left < 0)
|
|
left = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
QXTimer::resume()
|
|
{
|
|
if (left >= 0 && !timer.isActive()) {
|
|
timer.start( left, true );
|
|
gettimeofday( &stv, 0 );
|
|
}
|
|
}
|
|
|
|
void
|
|
QXTimer::slotTimeout()
|
|
{
|
|
left = 0;
|
|
emit timeout();
|
|
}
|
|
|
|
|
|
#include "kgverify.moc"
|