From b81e43465b14836b17e4fe2dea91c78a2bdd29b3 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sun, 22 Jan 2012 01:02:36 -0600 Subject: Part 2 of prior commit --- tdmlib/CMakeLists.txt | 85 ++++++ tdmlib/Makefile.am | 30 ++ tdmlib/dmctl.cpp | 442 ++++++++++++++++++++++++++++++ tdmlib/dmctl.h | 93 +++++++ tdmlib/kgreet_classic.cpp | 513 ++++++++++++++++++++++++++++++++++ tdmlib/kgreet_classic.h | 88 ++++++ tdmlib/kgreet_pam.cpp | 675 +++++++++++++++++++++++++++++++++++++++++++++ tdmlib/kgreet_pam.h | 94 +++++++ tdmlib/kgreet_winbind.cpp | 679 ++++++++++++++++++++++++++++++++++++++++++++++ tdmlib/kgreet_winbind.h | 101 +++++++ tdmlib/kgreeterplugin.h | 407 +++++++++++++++++++++++++++ tdmlib/tdmtsak.cpp | 180 ++++++++++++ tdmlib/tdmtsak.h | 144 ++++++++++ 13 files changed, 3531 insertions(+) create mode 100644 tdmlib/CMakeLists.txt create mode 100644 tdmlib/Makefile.am create mode 100644 tdmlib/dmctl.cpp create mode 100644 tdmlib/dmctl.h create mode 100644 tdmlib/kgreet_classic.cpp create mode 100644 tdmlib/kgreet_classic.h create mode 100644 tdmlib/kgreet_pam.cpp create mode 100644 tdmlib/kgreet_pam.h create mode 100644 tdmlib/kgreet_winbind.cpp create mode 100644 tdmlib/kgreet_winbind.h create mode 100644 tdmlib/kgreeterplugin.h create mode 100644 tdmlib/tdmtsak.cpp create mode 100644 tdmlib/tdmtsak.h (limited to 'tdmlib') diff --git a/tdmlib/CMakeLists.txt b/tdmlib/CMakeLists.txt new file mode 100644 index 000000000..a2565fe1d --- /dev/null +++ b/tdmlib/CMakeLists.txt @@ -0,0 +1,85 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/tdm/kfrontend + ${CMAKE_BINARY_DIR} + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + +if( BUILD_TDM ) + + +##### headers ################################### + +install( FILES kgreeterplugin.h DESTINATION ${INCLUDE_INSTALL_DIR} ) + + +##### kgreet_classic (module) ################### + +tde_add_kpart( kgreet_classic AUTOMOC + SOURCES kgreet_classic.cpp + LINK tdeui-shared + DESTINATION ${PLUGIN_INSTALL_DIR} +) + + +##### kgreet_pam (module) ####################### + +tde_add_kpart( kgreet_pam AUTOMOC + SOURCES kgreet_pam.cpp + LINK tdeui-shared + DESTINATION ${PLUGIN_INSTALL_DIR} +) + + +##### kgreet_winbind (module) ################### + +tde_add_kpart( kgreet_winbind AUTOMOC + SOURCES kgreet_winbind.cpp + LINK tdeui-shared + DESTINATION ${PLUGIN_INSTALL_DIR} +) + + + +endif( BUILD_TDM ) + + +##### dmctl (static) ############################ + +if( BUILD_KICKER OR BUILD_KDESKTOP OR BUILD_TDM OR BUILD_KSMSERVER ) + + tde_add_library( dmctl STATIC_PIC + SOURCES dmctl.cpp + LINK Xau + ) + +endif( ) + +##### tdmtsak (executable) ####################### + +if( BUILD_TSAK ) + tde_add_executable( tdmtsak + SOURCES tdmtsak.cpp + LINK ${TQT_LIBRARIES} + DESTINATION ${BIN_INSTALL_DIR} + SETUID + DESCRIPTION "Secure Attention Key interface for TDM" + AUTHORS "Timothy Pearson" + ) +endif( BUILD_TSAK ) diff --git a/tdmlib/Makefile.am b/tdmlib/Makefile.am new file mode 100644 index 000000000..f21f59bd5 --- /dev/null +++ b/tdmlib/Makefile.am @@ -0,0 +1,30 @@ +AM_CPPFLAGS = -I$(top_srcdir)/tdm/kfrontend $(all_includes) + +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_TDEUI) + +kgreet_pam_la_SOURCES = kgreet_pam.cpp +kgreet_pam_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries) +kgreet_pam_la_LIBADD = $(LIB_TDEUI) + +kgreet_winbind_la_SOURCES = kgreet_winbind.cpp +kgreet_winbind_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries) +kgreet_winbind_la_LIBADD = $(LIB_TDEUI) + +noinst_LTLIBRARIES = libdmctl.la +libdmctl_la_SOURCES = dmctl.cpp +libdmctl_la_LDFLAGS = $(all_libraries) -no-undefined +libdmctl_la_LIBADD = $(LIB_TDECORE) -lXau + +METASOURCES = AUTO + +noinst_HEADERS = dmctl.h kgreet_classic.h kgreet_winbind.h +include_HEADERS = kgreeterplugin.h + +messages: + $(XGETTEXT) $(kgreet_classic_la_SOURCES) -o $(podir)/kgreet_classic.pot + $(XGETTEXT) $(kgreet_winbind_la_SOURCES) -o $(podir)/kgreet_winbind.pot + $(XGETTEXT) $(libdmctl_la_SOURCES) -o $(podir)/libdmctl.pot diff --git a/tdmlib/dmctl.cpp b/tdmlib/dmctl.cpp new file mode 100644 index 000000000..41a5cb206 --- /dev/null +++ b/tdmlib/dmctl.cpp @@ -0,0 +1,442 @@ +/* + Copyright (C) 2004 Oswald Buddenhagen + + This program is free software; you can redistribute it and/or + modify it under the terms of the Lesser 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 Lesser GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "dmctl.h" + +#ifdef Q_WS_X11 + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static enum { Dunno, NoDM, NewTDM, OldTDM, GDM } DMType = Dunno; +static const char *ctl, *dpy; + +DM::DM() : fd( -1 ) +{ + char *ptr; + struct sockaddr_un sa; + + if (DMType == Dunno) { + if (!(dpy = ::getenv( "DISPLAY" ))) + DMType = NoDM; + else if ((ctl = ::getenv( "DM_CONTROL" ))) + DMType = NewTDM; + else if ((ctl = ::getenv( "XDM_MANAGED" )) && ctl[0] == '/') + DMType = OldTDM; + else if (::getenv( "GDMSESSION" )) + DMType = GDM; + else + DMType = NoDM; + } + switch (DMType) { + default: + return; + case NewTDM: + case GDM: + if ((fd = ::socket( PF_UNIX, SOCK_STREAM, 0 )) < 0) + return; + sa.sun_family = AF_UNIX; + if (DMType == GDM) { + strcpy( sa.sun_path, "/var/run/gdm_socket" ); + if (::connect( fd, (struct sockaddr *)&sa, sizeof(sa) )) { + strcpy( sa.sun_path, "/tmp/.gdm_socket" ); + if (::connect( fd, (struct sockaddr *)&sa, sizeof(sa) )) { + ::close( fd ); + fd = -1; + break; + } + } + 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 ); + if (::connect( fd, (struct sockaddr *)&sa, sizeof(sa) )) { + ::close( fd ); + fd = -1; + } + } + break; + case OldTDM: + { + TQString tf( ctl ); + tf.truncate( tf.find( ',' ) ); + fd = ::open( tf.latin1(), O_WRONLY ); + } + break; + } +} + +DM::~DM() +{ + if (fd >= 0) + close( fd ); +} + +bool +DM::exec( const char *cmd ) +{ + TQCString buf; + + return exec( cmd, buf ); +} + +/** + * Execute a TDM/GDM remote control command. + * @param cmd the command to execute. FIXME: undocumented yet. + * @param buf the result buffer. + * @return result: + * @li If true, the command was successfully executed. + * @p ret might contain addional results. + * @li If false and @p ret is empty, a communication error occurred + * (most probably TDM is not running). + * @li If false and @p ret is non-empty, it contains the error message + * from TDM. + */ +bool +DM::exec( const char *cmd, TQCString &buf ) +{ + bool ret = false; + int tl; + unsigned len = 0; + + if (fd < 0) + goto busted; + + tl = strlen( cmd ); + if (::write( fd, cmd, tl ) != tl) { + bust: + ::close( fd ); + fd = -1; + busted: + buf.resize( 0 ); + return false; + } + if (DMType == OldTDM) { + buf.resize( 0 ); + return true; + } + for (;;) { + if (buf.size() < 128) + buf.resize( 128 ); + else if (buf.size() < len * 2) + buf.resize( len * 2 ); + if ((tl = ::read( fd, buf.data() + len, buf.size() - len)) <= 0) { + if (tl < 0 && errno == EINTR) + continue; + goto bust; + } + len += tl; + if (buf[len - 1] == '\n') { + buf[len - 1] = 0; + if (len > 2 && (buf[0] == 'o' || buf[0] == 'O') && + (buf[1] == 'k' || buf[1] == 'K') && buf[2] <= 32) + ret = true; + break; + } + } + return ret; +} + +bool +DM::canShutdown() +{ + if (DMType == OldTDM) + return strstr( ctl, ",maysd" ) != 0; + + TQCString re; + + if (DMType == GDM) + return exec( "QUERY_LOGOUT_ACTION\n", re ) && re.find("HALT") >= 0; + + return exec( "caps\n", re ) && re.find( "\tshutdown" ) >= 0; +} + +void +DM::shutdown( KApplication::ShutdownType shutdownType, + KApplication::ShutdownMode shutdownMode, /* NOT Default */ + const TQString &bootOption ) +{ + if (shutdownType == KApplication::ShutdownTypeNone) + return; + + bool cap_ask; + if (DMType == NewTDM) { + TQCString re; + cap_ask = exec( "caps\n", re ) && re.find( "\tshutdown ask" ) >= 0; + } else { + if (!bootOption.isEmpty()) + return; + cap_ask = false; + } + if (!cap_ask && shutdownMode == KApplication::ShutdownModeInteractive) + shutdownMode = KApplication::ShutdownModeForceNow; + + TQCString cmd; + if (DMType == GDM) { + cmd.append( shutdownMode == KApplication::ShutdownModeForceNow ? + "SET_LOGOUT_ACTION " : "SET_SAFE_LOGOUT_ACTION " ); + cmd.append( shutdownType == KApplication::ShutdownTypeReboot ? + "REBOOT\n" : "HALT\n" ); + } else { + cmd.append( "shutdown\t" ); + cmd.append( shutdownType == KApplication::ShutdownTypeReboot ? + "reboot\t" : "halt\t" ); + if (!bootOption.isEmpty()) + cmd.append( "=" ).append( bootOption.local8Bit() ).append( "\t" ); + cmd.append( shutdownMode == KApplication::ShutdownModeInteractive ? + "ask\n" : + shutdownMode == KApplication::ShutdownModeForceNow ? + "forcenow\n" : + shutdownMode == KApplication::ShutdownModeTryNow ? + "trynow\n" : "schedule\n" ); + } + exec( cmd.data() ); +} + +bool +DM::bootOptions( TQStringList &opts, int &defopt, int ¤t ) +{ + if (DMType != NewTDM) + return false; + + TQCString re; + if (!exec( "listbootoptions\n", re )) + return false; + + opts = TQStringList::split( '\t', TQString::fromLocal8Bit( re.data() ) ); + if (opts.size() < 4) + return false; + + bool ok; + defopt = opts[2].toInt( &ok ); + if (!ok) + return false; + current = opts[3].toInt( &ok ); + if (!ok) + return false; + + opts = TQStringList::split( ' ', opts[1] ); + for (TQStringList::Iterator it = opts.begin(); it != opts.end(); ++it) + (*it).replace( "\\s", " " ); + + return true; +} + +void +DM::setLock( bool on ) +{ + if (DMType != GDM) + exec( on ? "lock\n" : "unlock\n" ); +} + +bool +DM::isSwitchable() +{ + if (DMType == OldTDM) + return dpy[0] == ':'; + + if (DMType == GDM) + return exec( "QUERY_VT\n" ); + + TQCString re; + + return exec( "caps\n", re ) && re.find( "\tlocal" ) >= 0; +} + +int +DM::numReserve() +{ + if (DMType == GDM) + return 1; /* Bleh */ + + if (DMType == OldTDM) + return strstr( ctl, ",rsvd" ) ? 1 : -1; + + TQCString re; + int p; + + if (!(exec( "caps\n", re ) && (p = re.find( "\treserve " )) >= 0)) + return -1; + return atoi( re.data() + p + 9 ); +} + +void +DM::startReserve() +{ + if (DMType == GDM) + exec("FLEXI_XSERVER\n"); + else + exec("reserve\n"); +} + +bool +DM::localSessions( SessList &list ) +{ + if (DMType == OldTDM) + return false; + + TQCString re; + + if (DMType == GDM) { + if (!exec( "CONSOLE_SERVERS\n", re )) + return false; + TQStringList sess = TQStringList::split( TQChar(';'), re.data() + 3 ); + for (TQStringList::ConstIterator it = sess.begin(); it != sess.end(); ++it) { + TQStringList ts = TQStringList::split( TQChar(','), *it, true ); + SessEnt se; + se.display = ts[0]; + se.user = ts[1]; + se.vt = ts[2].toInt(); + se.session = ""; + se.self = ts[0] == ::getenv( "DISPLAY" ); /* Bleh */ + se.tty = false; + list.append( se ); + } + } else { + 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 ); + SessEnt se; + se.display = ts[0]; + if (ts[1][0] == '@') + se.from = ts[1].mid( 1 ), se.vt = 0; + else + se.vt = ts[1].mid( 2 ).toInt(); + se.user = ts[2]; + se.session = ts[3]; + se.self = (ts[4].find( '*' ) >= 0); + se.tty = (ts[4].find( 't' ) >= 0); + list.append( se ); + } + } + return true; +} + +void +DM::sess2Str2( const SessEnt &se, TQString &user, TQString &loc ) +{ + if (se.tty) { + user = i18n("user: ...", "%1: TTY login").arg( se.user ); + loc = se.vt ? TQString(TQString("vt%1").arg( se.vt )) : se.display ; + } else { + user = + se.user.isEmpty() ? + se.session.isEmpty() ? + i18n("Unused") : + se.session == "" ? + i18n("X login on remote host") : + TQString(i18n("... host", "X login on %1").arg( se.session )) : + se.session == "" ? + se.user : + TQString(i18n("user: session type", "%1: %2") + .arg( se.user ).arg( se.session )); + loc = + se.vt ? + TQString(TQString("%1, vt%2").arg( se.display ).arg( se.vt )) : + se.display; + } +} + +TQString +DM::sess2Str( const SessEnt &se ) +{ + TQString user, loc; + + sess2Str2( se, user, loc ); + return i18n("session (location)", "%1 (%2)").arg( user ).arg( loc ); +} + +bool +DM::switchVT( int vt ) +{ + if (DMType == GDM) + return exec( TQString(TQString("SET_VT %1\n").arg(vt)).latin1() ); + + return exec( TQString(TQString("activate\tvt%1\n").arg(vt)).latin1() ); +} + +void +DM::lockSwitchVT( int vt ) +{ + if (switchVT( vt )) + kapp->dcopClient()->send( "kdesktop", "KScreensaverIface", "lock()", TQString("") ); +} + +void +DM::GDMAuthenticate() +{ + FILE *fp; + const char *dpy, *dnum, *dne; + int dnl; + Xauth *xau; + + dpy = DisplayString( TQPaintDevice::x11AppDisplay() ); + if (!dpy) { + dpy = ::getenv( "DISPLAY" ); + if (!dpy) + return; + } + dnum = strchr( dpy, ':' ) + 1; + dne = strchr( dpy, '.' ); + dnl = dne ? dne - dnum : strlen( dnum ); + + /* XXX should do locking */ + if (!(fp = fopen( XauFileName(), "r" ))) + return; + + while ((xau = XauReadAuth( fp ))) { + if (xau->family == FamilyLocal && + xau->number_length == dnl && !memcmp( xau->number, dnum, dnl ) && + xau->data_length == 16 && + xau->name_length == 18 && !memcmp( xau->name, "MIT-MAGIC-COOKIE-1", 18 )) + { + TQString cmd( "AUTH_LOCAL " ); + for (int i = 0; i < 16; i++) + cmd += TQString::number( (uchar)xau->data[i], 16 ).rightJustify( 2, '0'); + cmd += "\n"; + if (exec( cmd.latin1() )) { + XauDisposeAuth( xau ); + break; + } + } + XauDisposeAuth( xau ); + } + + fclose (fp); +} + +#endif // Q_WS_X11 diff --git a/tdmlib/dmctl.h b/tdmlib/dmctl.h new file mode 100644 index 000000000..da5aa2b0b --- /dev/null +++ b/tdmlib/dmctl.h @@ -0,0 +1,93 @@ +/* + Copyright (C) 2004,2005 Oswald Buddenhagen + Copyright (C) 2005 Stephan Kulow + + This program is free software; you can redistribute it and/or + modify it under the terms of the Lesser 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 Lesser GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef DMCTL_H +#define DMCTL_H + +#include + +struct SessEnt { + TQString display, from, user, session; + int vt; + bool self:1, tty:1; +}; + +typedef TQValueList SessList; + +class DM { + +#ifdef Q_WS_X11 + +public: + DM(); + ~DM(); + + bool canShutdown(); + void shutdown( KApplication::ShutdownType shutdownType, + KApplication::ShutdownMode shutdownMode, + const TQString &bootOption = TQString::null ); + + void setLock( bool on ); + + bool isSwitchable(); + int numReserve(); + void startReserve(); + bool localSessions( SessList &list ); + bool switchVT( int vt ); + void lockSwitchVT( int vt ); + + bool bootOptions( TQStringList &opts, int &dflt, int &curr ); + + static TQString sess2Str( const SessEnt &se ); + static void sess2Str2( const SessEnt &se, TQString &user, TQString &loc ); + +private: + int fd; + + bool exec( const char *cmd, TQCString &ret ); + bool exec( const char *cmd ); + + void GDMAuthenticate(); + +#else // Q_WS_X11 + +public: + DM() {} + + bool canShutdown() { return false; } + void shutdown( KApplication::ShutdownType shutdownType, + KApplication::ShutdownMode shutdownMode, + const TQString &bootOption = TQString::null ) {} + + void setLock( bool ) {} + + bool isSwitchable() { return false; } + int numReserve() { return -1; } + void startReserve() {} + bool localSessions( SessList &list ) { return false; } + void switchVT( int vt ) {} + + bool bootOptions( TQStringList &opts, int &dflt, int &curr ); + +#endif // Q_WS_X11 + +}; // class DM + +#endif // DMCTL_H diff --git a/tdmlib/kgreet_classic.cpp b/tdmlib/kgreet_classic.cpp new file mode 100644 index 000000000..b37f2bab7 --- /dev/null +++ b/tdmlib/kgreet_classic.cpp @@ -0,0 +1,513 @@ +/* + +Conversation widget for tdm 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_classic.h" +#include "themer/tdmthemer.h" +#include "themer/tdmitem.h" + +#include +#include +#include +#include + +#include +#include +#include + +class TDMPasswordEdit : public KPasswordEdit { +public: + TDMPasswordEdit( TQWidget *parent ) : KPasswordEdit( parent, 0 ) {} + TDMPasswordEdit( KPasswordEdit::EchoModes echoMode, TQWidget *parent ) : KPasswordEdit( echoMode, parent, 0 ) {} +protected: + virtual void contextMenuEvent( TQContextMenuEvent * ) {} +}; + +static int echoMode; + +KClassicGreeter::KClassicGreeter( KGreeterPluginHandler *_handler, + KdmThemer *themer, + TQWidget *parent, TQWidget *pred, + const TQString &_fixedEntity, + Function _func, Context _ctx ) : + TQObject(), + KGreeterPlugin( _handler ), + fixedUser( _fixedEntity ), + func( _func ), + ctx( _ctx ), + exp( -1 ), + pExp( -1 ), + running( false ) +{ + KdmItem *user_entry = 0, *pw_entry = 0; + TQGridLayout *grid = 0; + int line = 0; + + layoutItem = 0; + + if (themer && + (!(user_entry = themer->findNode( "user-entry" )) || + !(pw_entry = themer->findNode( "pw-entry" )))) + themer = 0; + + if (!themer) + grid = new TQGridLayout( 0, 0, 10 ); + layoutItem = TQT_TQLAYOUTITEM(grid); + + loginLabel = passwdLabel = passwd1Label = passwd2Label = 0; + loginEdit = 0; + passwdEdit = passwd1Edit = passwd2Edit = 0; + if (ctx == ExUnlock || ctx == ExChangeTok) + fixedUser = KUser().loginName(); + if (func != ChAuthTok) { + if (fixedUser.isEmpty()) { + loginEdit = new KLineEdit( parent ); + loginEdit->setContextMenuEnabled( false ); + connect( loginEdit, TQT_SIGNAL(lostFocus()), TQT_SLOT(slotLoginLostFocus()) ); + connect( loginEdit, TQT_SIGNAL(lostFocus()), TQT_SLOT(slotActivity()) ); + connect( loginEdit, TQT_SIGNAL(textChanged( const TQString & )), TQT_SLOT(slotActivity()) ); + connect( loginEdit, TQT_SIGNAL(selectionChanged()), TQT_SLOT(slotActivity()) ); + if (pred) { + parent->setTabOrder( pred, loginEdit ); + pred = loginEdit; + } + if (!grid) { + loginEdit->adjustSize(); + user_entry->setWidget( loginEdit ); + } else { + loginLabel = new TQLabel( loginEdit, i18n("&Username:"), parent ); + grid->addWidget( loginLabel, line, 0 ); + grid->addWidget( loginEdit, line++, 1 ); + } + } else if (ctx != Login && ctx != Shutdown && grid) { + loginLabel = new TQLabel( i18n("Username:"), parent ); + grid->addWidget( loginLabel, line, 0 ); + grid->addWidget( new TQLabel( fixedUser, parent ), line++, 1 ); + } + if (echoMode == -1) + passwdEdit = new TDMPasswordEdit( parent ); + else + passwdEdit = new TDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, + parent ); + connect( passwdEdit, TQT_SIGNAL(textChanged( const TQString & )), + TQT_SLOT(slotActivity()) ); + connect( passwdEdit, TQT_SIGNAL(lostFocus()), TQT_SLOT(slotActivity()) ); + if (pred) { + parent->setTabOrder( pred, passwdEdit ); + pred = passwdEdit; + } + if (!grid) { + passwdEdit->adjustSize(); + pw_entry->setWidget( passwdEdit ); + } else { + passwdLabel = new TQLabel( passwdEdit, + func == Authenticate ? + i18n("&Password:") : + i18n("Current &password:"), + parent ); + 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 TDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, parent ); + passwd2Edit = new TDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, parent ); + } else { + passwd1Edit = new TDMPasswordEdit( parent ); + passwd2Edit = new TDMPasswordEdit( parent ); + } + passwd1Label = new TQLabel( passwd1Edit, i18n("&New password:"), parent ); + passwd2Label = new TQLabel( 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 +KClassicGreeter::~KClassicGreeter() +{ + abort(); + if (!layoutItem) { + delete loginEdit; + delete passwdEdit; + return; + } + TQLayoutIterator it = TQT_TQLAYOUT(layoutItem)->iterator(); + for (TQLayoutItem *itm = it.current(); itm; itm = ++it) + delete itm->widget(); + delete layoutItem; +} + +void // virtual +KClassicGreeter::loadUsers( const TQStringList &users ) +{ + KCompletion *userNamesCompletion = new KCompletion; + userNamesCompletion->setItems( users ); + loginEdit->setCompletionObject( userNamesCompletion ); + loginEdit->setAutoDeleteCompletionObject( true ); + loginEdit->setCompletionMode( KGlobalSettings::CompletionAuto ); +} + +void // virtual +KClassicGreeter::presetEntity( const TQString &entity, int field ) +{ + loginEdit->setText( entity ); + if (field == 1) + passwdEdit->setFocus(); + else { + loginEdit->setFocus(); + loginEdit->selectAll(); + if (field == -1) { + passwdEdit->setText( " " ); + passwdEdit->setEnabled( false ); + authTok = false; + } + } + curUser = entity; +} + +TQString // virtual +KClassicGreeter::getEntity() const +{ + return fixedUser.isEmpty() ? loginEdit->text() : fixedUser; +} + +void // virtual +KClassicGreeter::setUser( const TQString &user ) +{ + // assert( fixedUser.isEmpty() ); + curUser = user; + loginEdit->setText( user ); + passwdEdit->setFocus(); + passwdEdit->selectAll(); +} + +void // virtual +KClassicGreeter::setPassword( const TQString &pass ) +{ + passwdEdit->erase(); + passwdEdit->insert( pass ); +} + +void // virtual +KClassicGreeter::setEnabled( bool enable ) +{ + // assert( !passwd1Label ); + // assert( func == Authenticate && ctx == Shutdown ); +// if (loginLabel) +// loginLabel->setEnabled( enable ); + passwdLabel->setEnabled( enable ); + setActive( enable ); + if (enable) + passwdEdit->setFocus(); +} + +void // private +KClassicGreeter::returnData() +{ + switch (exp) { + case 0: + handler->gplugReturnText( (loginEdit ? loginEdit->text() : + fixedUser).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 +KClassicGreeter::textMessage( const char *text, bool err ) +{ + if (!err && + TQString( text ).find( TQRegExp( "^Changing password for [^ ]+$" ) ) >= 0) + return true; + return false; +} + +void // virtual +KClassicGreeter::textPrompt( const char *prompt, bool echo, bool nonBlocking ) +{ + pExp = exp; + if (echo) + exp = 0; + else if (!authTok) + exp = 1; + else { + TQString pr( prompt ); + if (pr.find( TQRegExp( "\\bpassword\\b", false ) ) >= 0) { + if (pr.find( TQRegExp( "\\b(re-?(enter|type)|again|confirm|repeat)\\b", + false ) ) >= 0) + exp = 3; + else if (pr.find( TQRegExp( "\\bnew\\b", false ) ) >= 0) + exp = 2; + else { // TQRegExp( "\\b(old|current)\\b", false ) is too strict + handler->gplugReturnText( "", + KGreeterPluginHandler::IsOldPassword | + KGreeterPluginHandler::IsSecret ); + return; + } + } else { + handler->gplugMsgBox( TQMessageBox::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 +KClassicGreeter::binaryPrompt( const char *, bool ) +{ + // this simply cannot happen ... :} + return true; +} + +void // virtual +KClassicGreeter::start() +{ + authTok = !(passwdEdit && passwdEdit->isEnabled()); + exp = has = -1; + running = true; +} + +void // virtual +KClassicGreeter::suspend() +{ +} + +void // virtual +KClassicGreeter::resume() +{ +} + +void // virtual +KClassicGreeter::next() +{ + // 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(); + else if (has >= exp) + returnData(); +} + +void // virtual +KClassicGreeter::abort() +{ + running = false; + if (exp >= 0) { + exp = -1; + handler->gplugReturnText( 0, 0 ); + } +} + +void // virtual +KClassicGreeter::succeeded() +{ + // assert( running || timed_login ); + if (!authTok) { + setActive( false ); + if (passwd1Edit) { + authTok = true; + return; + } + } else + setActive2( false ); + exp = -1; + running = false; +} + +void // virtual +KClassicGreeter::failed() +{ + // assert( running || timed_login ); + setActive( false ); + setActive2( false ); + exp = -1; + running = false; +} + +void // virtual +KClassicGreeter::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 +KClassicGreeter::clear() +{ + // assert( !running && !passwd1Edit ); + passwdEdit->erase(); + if (loginEdit) { + loginEdit->clear(); + loginEdit->setFocus(); + curUser = TQString::null; + } else + passwdEdit->setFocus(); +} + + +// private + +void +KClassicGreeter::setActive( bool enable ) +{ + if (loginEdit) + loginEdit->setEnabled( enable ); + if (passwdEdit) + passwdEdit->setEnabled( enable ); +} + +void +KClassicGreeter::setActive2( bool enable ) +{ + if (passwd1Edit) { + passwd1Edit->setEnabled( enable ); + passwd2Edit->setEnabled( enable ); + } +} + +void +KClassicGreeter::slotLoginLostFocus() +{ + if (!running) + return; + if (exp > 0) { + if (curUser == loginEdit->text()) + return; + exp = -1; + handler->gplugReturnText( 0, 0 ); + } + curUser = loginEdit->text(); + handler->gplugSetUser( curUser ); +} + +void +KClassicGreeter::slotActivity() +{ + if (running) + handler->gplugActivity(); +} + +// factory + +static bool init( const TQString &, + TQVariant (*getConf)( void *, const char *, const TQVariant & ), + void *ctx ) +{ + echoMode = getConf( ctx, "EchoMode", TQVariant( -1 ) ).toInt(); + KGlobal::locale()->insertCatalogue( "kgreet_classic" ); + return true; +} + +static void done( void ) +{ + KGlobal::locale()->removeCatalogue( "kgreet_classic" ); +} + +static KGreeterPlugin * +create( KGreeterPluginHandler *handler, KdmThemer *themer, + TQWidget *parent, TQWidget *predecessor, + const TQString &fixedEntity, + KGreeterPlugin::Function func, + KGreeterPlugin::Context ctx ) +{ + return new KClassicGreeter( handler, themer, parent, predecessor, fixedEntity, func, ctx ); +} + +KDE_EXPORT kgreeterplugin_info kgreeterplugin_info = { + I18N_NOOP("Username + password (classic)"), "classic", + kgreeterplugin_info::Local | kgreeterplugin_info::Presettable, + init, done, create +}; + +#include "kgreet_classic.moc" diff --git a/tdmlib/kgreet_classic.h b/tdmlib/kgreet_classic.h new file mode 100644 index 000000000..1f467a528 --- /dev/null +++ b/tdmlib/kgreet_classic.h @@ -0,0 +1,88 @@ +/* + +Conversation widget for tdm greeter + +Copyright (C) 1997, 1998 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. + +*/ + + +#ifndef KGREET_CLASSIC_H +#define KGREET_CLASSIC_H + +#include "kgreeterplugin.h" + +#include + +class KLineEdit; +class KPasswordEdit; +class KSimpleConfig; +class TQGridLayout; +class TQLabel; + +class KClassicGreeter : public TQObject, public KGreeterPlugin { + Q_OBJECT + + public: + KClassicGreeter( KGreeterPluginHandler *handler, + KdmThemer *themer, + TQWidget *parent, TQWidget *predecessor, + const TQString &fixedEntitiy, + Function func, Context ctx ); + ~KClassicGreeter(); + virtual void loadUsers( const TQStringList &users ); + virtual void presetEntity( const TQString &entity, int field ); + virtual TQString getEntity() const; + virtual void setUser( const TQString &user ); + virtual void setPassword( const TQString &pass ); + 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(); + + public slots: + void slotLoginLostFocus(); + void slotActivity(); + + private: + void setActive( bool enable ); + void setActive2( bool enable ); + void returnData(); + + TQLabel *loginLabel, *passwdLabel, *passwd1Label, *passwd2Label; + KLineEdit *loginEdit; + KPasswordEdit *passwdEdit, *passwd1Edit, *passwd2Edit; + KSimpleConfig *stsFile; + TQString fixedUser, curUser; + Function func; + Context ctx; + int exp, pExp, has; + bool running, authTok; +}; + +#endif /* KGREET_CLASSIC_H */ diff --git a/tdmlib/kgreet_pam.cpp b/tdmlib/kgreet_pam.cpp new file mode 100644 index 000000000..82506fb43 --- /dev/null +++ b/tdmlib/kgreet_pam.cpp @@ -0,0 +1,675 @@ +/* + +Conversation widget for tdm greeter + +Copyright (C) 2008 Dirk Mueller + +based on classic tdm 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/tdmthemer.h" +#include "themer/tdmlabel.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +//#define PAM_GREETER_DEBUG + +class TDMPasswordEdit : public KPasswordEdit { +public: + TDMPasswordEdit( TQWidget *parent ) : KPasswordEdit( parent, 0 ) {} + TDMPasswordEdit( KPasswordEdit::EchoModes echoMode, TQWidget *parent ) : KPasswordEdit( echoMode, parent, 0 ) {} +protected: + virtual void contextMenuEvent( TQContextMenuEvent * ) {} +}; + +static FILE* log; +static void kg_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, + TQWidget *parent, TQWidget *pred, + const TQString &_fixedEntity, + Function _func, Context _ctx ) : + TQObject(), + KGreeterPlugin( _handler ), + fixedUser( _fixedEntity ), + func( _func ), + ctx( _ctx ), + exp( -1 ), + pExp( -1 ), + running( false ) +{ + ctx = Login; + + kg_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 = TQT_TQLAYOUTITEM(new TQGridLayout( 0, 0, 10 )); + + loginLabel = 0; + authLabel.clear(); + authEdit.clear(); + loginLabel = 0; + loginEdit = 0; + if (ctx == ExUnlock || ctx == ExChangeTok) + fixedUser = KUser().loginName(); + if (func != ChAuthTok) { + kg_debug("func != ChAuthTok\n"); + kg_debug("fixedUser: *%s*\n", fixedUser.latin1()); + + if (fixedUser.isEmpty()) { + loginEdit = new KLineEdit( parent ); + loginEdit->setContextMenuEnabled( false ); + connect( loginEdit, TQT_SIGNAL(lostFocus()), TQT_SLOT(slotLoginLostFocus()) ); + connect( loginEdit, TQT_SIGNAL(lostFocus()), TQT_SLOT(slotActivity()) ); + connect( loginEdit, TQT_SIGNAL(textChanged( const TQString & )), TQT_SLOT(slotActivity()) ); + connect( loginEdit, TQT_SIGNAL(selectionChanged()), TQT_SLOT(slotActivity()) ); + if (pred) { + parent->setTabOrder( pred, loginEdit ); + pred = loginEdit; + } + if (!getLayoutItem()) { + loginEdit->adjustSize(); + user_entry->setWidget( loginEdit ); + } else { + loginLabel = new TQLabel( loginEdit, i18n("Username:"), parent ); + getLayoutItem()->addWidget( loginLabel, line, 0 ); + getLayoutItem()->addWidget( loginEdit, line++, 1 ); + } + } else if (ctx != Login && ctx != Shutdown && getLayoutItem()) { + loginLabel = new TQLabel( i18n("Username:"), parent ); + getLayoutItem()->addWidget( loginLabel, line, 0 ); + getLayoutItem()->addWidget( new TQLabel( fixedUser, parent ), line++, 1 ); + } +#if 0 + if (echoMode == -1) + passwdEdit = new TDMPasswordEdit( parent ); + else + passwdEdit = new TDMPasswordEdit( echoMode, + parent ); + connect( passwdEdit, TQT_SIGNAL(textChanged( const TQString & )), + TQT_SLOT(slotActivity()) ); + connect( passwdEdit, TQT_SIGNAL(lostFocus()), TQT_SLOT(slotActivity()) ); + if (pred) { + parent->setTabOrder( pred, passwdEdit ); + pred = passwdEdit; + } + if (!getLayoutItem()) { + passwdEdit->adjustSize(); + pw_entry->setWidget( passwdEdit ); + } else { + passwdLabel = new TQLabel( 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 TDMPasswordEdit( echoMode, parent ); + authEdit << new TDMPasswordEdit( echoMode, parent ); + } else { + authEdit << new TDMPasswordEdit( parent ); + authEdit << new TDMPasswordEdit( parent ); + } + authLabel << new TQLabel( authEdit[0], i18n("&New password:"), parent ); + authLabel << new TQLabel( 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() +{ + kg_debug("KPamGreeter::~KPamGreeter"); + abort(); + if (!layoutItem) { + delete loginEdit; + return; + } + TQLayoutIterator it = TQT_TQLAYOUT(layoutItem)->iterator(); + for (TQLayoutItem *itm = it.current(); itm; itm = ++it) + delete itm->widget(); + delete layoutItem; + kg_debug("destructor finished, good bye"); +} + +void // virtual +KPamGreeter::loadUsers( const TQStringList &users ) +{ + KCompletion *userNamesCompletion = new KCompletion; + userNamesCompletion->setItems( users ); + loginEdit->setCompletionObject( userNamesCompletion ); + loginEdit->setAutoDeleteCompletionObject( true ); + loginEdit->setCompletionMode( KGlobalSettings::CompletionAuto ); +} + +void // virtual +KPamGreeter::presetEntity( const TQString &entity, int field ) +{ + kg_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; +} + +TQString // virtual +KPamGreeter::getEntity() const +{ + return fixedUser.isEmpty() ? loginEdit->text() : fixedUser; +} + +void // virtual +KPamGreeter::setUser( const TQString &user ) +{ + // assert( fixedUser.isEmpty() ); + curUser = user; + loginEdit->setText( user ); + if (authEdit.size() >= 1) { + authEdit[0]->setFocus(); + authEdit[0]->selectAll(); + } +} + +void // virtual +KPamGreeter::setPassword( const TQString &pass ) +{ + authEdit[0]->erase(); + authEdit[0]->insert( pass ); +} + +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() +{ + kg_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 ) +{ + kg_debug(" ************** textMessage(%s, %d)\n", text, err); + + if (!authEdit.size()) + return false; + + if (getLayoutItem()) { + TQLabel* label = new TQLabel(TQString::fromUtf8(text), m_parentWidget); + getLayoutItem()->addWidget(label, state+1, 0, 0); + } + + return true; +} + +void // virtual +KPamGreeter::textPrompt( const char *prompt, bool echo, bool nonBlocking ) +{ + kg_debug("textPrompt called with prompt %s echo %d nonBlocking %d", prompt, echo, nonBlocking); + kg_debug("state is %d, authEdit.size is %d\n", state, authEdit.size()); + + if (state == 0 && echo) { + if (loginLabel) + loginLabel->setText(TQString::fromUtf8(prompt)); + else if (m_themer) { + KdmLabel *tdmlabel = static_cast(m_themer->findNode("user-label")); + if (tdmlabel) { + //userLabel->setText(TQString::fromUtf8(prompt)); + tdmlabel->label.text = TQString::fromUtf8(prompt); + TQTimer::singleShot(0, tdmlabel, TQT_SLOT(update())); + } + } + } + else if (state >= authEdit.size()) { + if (getLayoutItem()) { + TQLabel* label = new TQLabel(TQString::fromUtf8(prompt), m_parentWidget); + getLayoutItem()->addWidget(label, state+1, 0, 0); + kg_debug("added label widget to layout"); + } + else if (m_themer) { + kg_debug("themer found!"); + KdmItem *pw_label = 0; + + KdmLabel *tdmlabel = static_cast(m_themer->findNode("pw-label")); + if (tdmlabel) { + //userLabel->setText(TQString::fromUtf8(prompt)); + TQString str = TQString::fromUtf8(prompt); + tdmlabel->label.text = str; + TQTimer::singleShot(0, tdmlabel, TQT_SLOT(update())); + } + } + + TDMPasswordEdit* passwdEdit; + + if (echoMode == -1) + passwdEdit = new TDMPasswordEdit( m_parentWidget ); + else + passwdEdit = new TDMPasswordEdit( echoMode, m_parentWidget); + connect( passwdEdit, TQT_SIGNAL(textChanged( const TQString & )), + TQT_SLOT(slotActivity()) ); + connect( passwdEdit, TQT_SIGNAL(lostFocus()), TQT_SLOT(slotActivity()) ); + authEdit << passwdEdit; + +#if 1 + for(TQValueList::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) { + kg_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(TQString::fromUtf8(prompt)); + //tdmlabel->label.text = TQString::fromUtf8(prompt); + //TQTimer::singleShot(0, tdmlabel, TQT_SLOT(update())); + } + } + else + kg_debug("no themer found!"); + } + ++state; + pExp = exp; + + exp = authEdit.size(); + kg_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() +{ + kg_debug("******* start() called\n"); + + while(authEdit.begin() != authEdit.end()) { + KPasswordEdit* item = *authEdit.remove(authEdit.begin()); + delete item; + } + + while(authLabel.begin() != authLabel.end()) { + TQLabel* 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() +{ + kg_debug("********* next() called state %d\n", state); + + if (state == 0 && running && handler) { + kg_debug(" **** returned text!\n"); + handler->gplugReturnText( (loginEdit ? loginEdit->text() : + fixedUser).local8Bit(), + KGreeterPluginHandler::IsUser ); + setActive(false); + } + + has = 0; + + for(TQValueList::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; + } + + kg_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() +{ + kg_debug("***** abort() called\n"); + + running = false; + if (exp >= 0) { + exp = -1; + handler->gplugReturnText( 0, 0 ); + } +} + +void // virtual +KPamGreeter::succeeded() +{ + kg_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 = TQString::null; + } else + authEdit[0]->setFocus(); +} + + +// private + +void +KPamGreeter::setActive( bool enable ) +{ + if (loginEdit) + loginEdit->setEnabled( enable ); +} + +void +KPamGreeter::setAllActive( bool enable ) +{ + for(TQValueList::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(); + kg_debug("curUser is %s", curUser.latin1()); + handler->gplugSetUser( curUser ); +} + +void +KPamGreeter::slotActivity() +{ + kg_debug("slotActivity"); + + if (running) + handler->gplugActivity(); +} + +// factory + +static bool init( const TQString &, + TQVariant (*getConf)( void *, const char *, const TQVariant & ), + void *ctx ) +{ + echoMode = (KPasswordEdit::EchoModes) getConf( ctx, "EchoMode", TQVariant( -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, + TQWidget *parent, TQWidget *predecessor, + const TQString &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" diff --git a/tdmlib/kgreet_pam.h b/tdmlib/kgreet_pam.h new file mode 100644 index 000000000..03c404c1e --- /dev/null +++ b/tdmlib/kgreet_pam.h @@ -0,0 +1,94 @@ +/* + +Conversation widget for tdm 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 TQGridLayout; +class TQLabel; + +class KPamGreeter : public TQObject, public KGreeterPlugin { + Q_OBJECT + + public: + KPamGreeter( KGreeterPluginHandler *handler, + KdmThemer *themer, + TQWidget *parent, TQWidget *predecessor, + const TQString &fixedEntitiy, + Function func, Context ctx ); + ~KPamGreeter(); + virtual void loadUsers( const TQStringList &users ); + virtual void presetEntity( const TQString &entity, int field ); + virtual TQString getEntity() const; + virtual void setUser( const TQString &user ); + virtual void setPassword( const TQString &pass ); + 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(); + + TQGridLayout *getLayoutItem() const { return static_cast(TQT_TQLAYOUT(layoutItem)); } + + public slots: + void slotLoginLostFocus(); + void slotActivity(); + + private: + void setActive( bool enable ); + void setAllActive( bool enable ); + void returnData(); + + TQLabel *loginLabel; + TQValueList authLabel; + KLineEdit *loginEdit; + TQWidget* m_parentWidget; + TQValueList authEdit; + KSimpleConfig *stsFile; + KdmThemer *m_themer; + TQString fixedUser, curUser; + Function func; + Context ctx; + int exp, pExp, has; + unsigned state; + bool running, authTok; +}; + +#endif /* KGREET_CLASSIC_H */ diff --git a/tdmlib/kgreet_winbind.cpp b/tdmlib/kgreet_winbind.cpp new file mode 100644 index 000000000..d5626a3fd --- /dev/null +++ b/tdmlib/kgreet_winbind.cpp @@ -0,0 +1,679 @@ +/* + +Conversation widget for tdm greeter + +Copyright (C) 1997, 1998, 2000 Steffen Hansen +Copyright (C) 2000-2004 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_winbind.h" +#include "themer/tdmthemer.h" +#include "themer/tdmitem.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +class TDMPasswordEdit : public KPasswordEdit { +public: + TDMPasswordEdit( TQWidget *parent ) : KPasswordEdit( parent, 0 ) {} + TDMPasswordEdit( KPasswordEdit::EchoModes echoMode, TQWidget *parent ) : KPasswordEdit( echoMode, parent, 0 ) {} +protected: + virtual void contextMenuEvent( TQContextMenuEvent * ) {} +}; + +static int echoMode; +static char separator; +static TQStringList staticDomains; +static TQString defaultDomain; + +static void +splitEntity( const TQString &ent, TQString &dom, TQString &usr ) +{ + int pos = ent.find( separator ); + if (pos < 0) + dom = "", usr = ent; + else + dom = ent.left( pos ), usr = ent.mid( pos + 1 ); +} + +KWinbindGreeter::KWinbindGreeter( KGreeterPluginHandler *_handler, + KdmThemer *themer, + TQWidget *parent, TQWidget *pred, + const TQString &_fixedEntity, + Function _func, Context _ctx ) : + TQObject(), + KGreeterPlugin( _handler ), + func( _func ), + ctx( _ctx ), + exp( -1 ), + pExp( -1 ), + running( false ) +{ + KdmItem *user_entry = 0, *pw_entry = 0, *domain_entry = 0; + TQGridLayout *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) + grid = new TQGridLayout( 0, 0, 10 ); + layoutItem = TQT_TQLAYOUTITEM(grid); + + 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, TQT_SIGNAL(activated( const TQString & )), + TQT_SLOT(slotChangedDomain( const TQString & )) ); + connect( domainCombo, TQT_SIGNAL(activated( const TQString & )), + TQT_SLOT(slotLoginLostFocus()) ); + connect( domainCombo, TQT_SIGNAL(activated( const TQString & )), + TQT_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 TQLabel( domainCombo, i18n("&Domain:"), parent ); + loginLabel = new TQLabel( 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, TQT_SIGNAL(lostFocus()), TQT_SLOT(slotLoginLostFocus()) ); + connect( loginEdit, TQT_SIGNAL(lostFocus()), TQT_SLOT(slotActivity()) ); + connect( loginEdit, TQT_SIGNAL(textChanged( const TQString & )), TQT_SLOT(slotActivity()) ); + connect( loginEdit, TQT_SIGNAL(selectionChanged()), TQT_SLOT(slotActivity()) ); + connect(&mDomainListTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotStartDomainList())); + domainCombo->insertStringList( staticDomains ); + TQTimer::singleShot(0, this, TQT_SLOT(slotStartDomainList())); + } else if (ctx != Login && ctx != Shutdown && grid) { + domainLabel = new TQLabel( i18n("Domain:"), parent ); + grid->addWidget( domainLabel, line, 0 ); + grid->addWidget( new TQLabel( fixedDomain, parent ), line++, 1 ); + loginLabel = new TQLabel( i18n("Username:"), parent ); + grid->addWidget( loginLabel, line, 0 ); + grid->addWidget( new TQLabel( fixedUser, parent ), line++, 1 ); + } + if (echoMode == -1) + passwdEdit = new TDMPasswordEdit( parent ); + else + passwdEdit = new TDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, + parent ); + connect( passwdEdit, TQT_SIGNAL(textChanged( const TQString & )), + TQT_SLOT(slotActivity()) ); + connect( passwdEdit, TQT_SIGNAL(lostFocus()), TQT_SLOT(slotActivity()) ); + + if (!grid) { + passwdEdit->adjustSize(); + pw_entry->setWidget( passwdEdit ); + } else { + passwdLabel = new TQLabel( 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 TDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, parent ); + passwd2Edit = new TDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, parent ); + } else { + passwd1Edit = new TDMPasswordEdit( parent ); + passwd2Edit = new TDMPasswordEdit( parent ); + } + passwd1Label = new TQLabel( passwd1Edit, i18n("&New password:"), parent ); + passwd2Label = new TQLabel( 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; + } + TQLayoutIterator it = TQT_TQLAYOUT(layoutItem)->iterator(); + for (TQLayoutItem *itm = it.current(); itm; itm = ++it) + delete itm->widget(); + delete layoutItem; + delete m_domainLister; +} + +void +KWinbindGreeter::slotChangedDomain( const TQString &dom ) +{ + if (!loginEdit->completionObject()) + return; + TQStringList users; + if (dom == "") { + for (TQStringList::ConstIterator it = allUsers.begin(); it != allUsers.end(); ++it) + if ((*it).find( separator ) < 0) + users << *it; + } else { + TQString st( dom + separator ); + for (TQStringList::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 TQStringList &users ) +{ + allUsers = users; + KCompletion *userNamesCompletion = new KCompletion; + loginEdit->setCompletionObject( userNamesCompletion ); + loginEdit->setAutoDeleteCompletionObject( true ); + loginEdit->setCompletionMode( KGlobalSettings::CompletionAuto ); + slotChangedDomain( defaultDomain ); +} + +void // virtual +KWinbindGreeter::presetEntity( const TQString &entity, int field ) +{ + TQString 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; +} + +TQString // virtual +KWinbindGreeter::getEntity() const +{ + TQString dom, usr; + if (fixedUser.isEmpty()) + dom = domainCombo->currentText(), usr = loginEdit->text(); + else + dom = fixedDomain, usr = fixedUser; + return dom == "" ? usr : dom + separator + usr; +} + +void // virtual +KWinbindGreeter::setUser( const TQString &user ) +{ + // assert (fixedUser.isEmpty()); + curUser = user; + TQString dom, usr; + splitEntity( user, dom, usr ); + domainCombo->setCurrentItem( dom, true ); + slotChangedDomain( dom ); + loginEdit->setText( usr ); + passwdEdit->setFocus(); + passwdEdit->selectAll(); +} + +void // virtual +KWinbindGreeter::setPassword( const TQString &pass ) +{ + passwdEdit->erase(); + passwdEdit->insert( pass ); +} + +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 && + TQString( text ).find( TQRegExp( "^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 { + TQString pr( prompt ); + if (pr.find( TQRegExp( "\\b(old|current)\\b", false ) ) >= 0) { + handler->gplugReturnText( "", + KGreeterPluginHandler::IsOldPassword | + KGreeterPluginHandler::IsSecret ); + return; + } else if (pr.find( TQRegExp( "\\b(re-?(enter|type)|again|confirm|repeat)\\b", + false ) ) >= 0) + exp = 3; + else if (pr.find( TQRegExp( "\\bnew\\b", false ) ) >= 0) + exp = 2; + else { + handler->gplugMsgBox( TQMessageBox::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 = TQString::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; + TQString 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, TQT_SIGNAL(readReady(KProcIO*)), TQT_SLOT(slotReadDomainList())); + connect(m_domainLister, TQT_SIGNAL(processExited(KProcess*)), TQT_SLOT(slotEndDomainList())); + + (*m_domainLister) << "wbinfo" << "--own-domain" << "--trusted-domains"; + m_domainLister->setComm (KProcess::Stdout); + m_domainLister->start(); +} + +void +KWinbindGreeter::slotReadDomainList() +{ + TQString line; + + while ( m_domainLister->readln( line ) != -1 ) { + mDomainListing.append(line); + } +} + +void +KWinbindGreeter::slotEndDomainList() +{ + delete m_domainLister; + m_domainLister = 0; + + TQStringList domainList; + domainList = staticDomains; + + for (TQStringList::const_iterator it = mDomainListing.begin(); + it != mDomainListing.end(); ++it) { + + if (!domainList.contains(*it)) + domainList.append(*it); + } + + TQString 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 TQString &, + TQVariant (*getConf)( void *, const char *, const TQVariant & ), + void *ctx ) +{ + echoMode = getConf( ctx, "EchoMode", TQVariant( -1 ) ).toInt(); + staticDomains = TQStringList::split( ':', getConf( ctx, "winbind.Domains", TQVariant( "" ) ).toString() ); + if (!staticDomains.contains("")) + staticDomains << ""; + + defaultDomain = getConf( ctx, "winbind.DefaultDomain", TQVariant( staticDomains.first() ) ).toString(); + TQString sepstr = getConf( ctx, "winbind.Separator", TQVariant( TQString::null ) ).toString(); + if (sepstr.isNull()) { + FILE *sepfile = popen( "wbinfo --separator 2>/dev/null", "r" ); + if (sepfile) { + TQTextIStream( 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 = TQString::null; +} + +static KGreeterPlugin * +create( KGreeterPluginHandler *handler, KdmThemer *themer, + TQWidget *parent, TQWidget *predecessor, + const TQString &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" diff --git a/tdmlib/kgreet_winbind.h b/tdmlib/kgreet_winbind.h new file mode 100644 index 000000000..54f2653fc --- /dev/null +++ b/tdmlib/kgreet_winbind.h @@ -0,0 +1,101 @@ +/* + +Conversation widget for tdm greeter + +Copyright (C) 1997, 1998 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. + +*/ + + +#ifndef KGREET_WINBIND_H +#define KGREET_WINBIND_H + +#include "kgreeterplugin.h" + +#include +#include + +class KComboBox; +class KLineEdit; +class KPasswordEdit; +class KSimpleConfig; +class TQGridLayout; +class TQLabel; +class KdmThemer; +class KProcIO; + +class KWinbindGreeter : public TQObject, public KGreeterPlugin { + Q_OBJECT + + public: + KWinbindGreeter( KGreeterPluginHandler *handler, + KdmThemer *themer, + TQWidget *parent, TQWidget *predecessor, + const TQString &fixedEntitiy, + Function func, Context ctx ); + ~KWinbindGreeter(); + virtual void loadUsers( const TQStringList &users ); + virtual void presetEntity( const TQString &entity, int field ); + virtual TQString getEntity() const; + virtual void setUser( const TQString &user ); + virtual void setPassword( const TQString &pass ); + 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(); + + public slots: + void slotLoginLostFocus(); + void slotChangedDomain( const TQString &dom ); + void slotActivity(); + void slotStartDomainList(); + void slotReadDomainList(); + void slotEndDomainList(); + + private: + void setActive( bool enable ); + void setActive2( bool enable ); + void returnData(); + + TQLabel *domainLabel, *loginLabel, *passwdLabel, *passwd1Label, *passwd2Label; + KComboBox *domainCombo; + KLineEdit *loginEdit; + KPasswordEdit *passwdEdit, *passwd1Edit, *passwd2Edit; + KSimpleConfig *stsFile; + TQString fixedDomain, fixedUser, curUser; + TQStringList allUsers, mDomainListing; + KProcIO* m_domainLister; + TQTimer mDomainListTimer; + + Function func; + Context ctx; + int exp, pExp, has; + bool running, authTok; +}; + +#endif /* KGREET_WINBIND_H */ diff --git a/tdmlib/kgreeterplugin.h b/tdmlib/kgreeterplugin.h new file mode 100644 index 000000000..edf67f141 --- /dev/null +++ b/tdmlib/kgreeterplugin.h @@ -0,0 +1,407 @@ +/* + + Authentication method specific conversation plugin for KDE's greeter widgets + + Copyright (C) 2003 Oswald Buddenhagen + Copyright (C) 2003 Fabian Kaiser + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KGREETERPLUGIN_H +#define KGREETERPLUGIN_H + +#include +#include +#include + +class KdmThemer; + +class TQWidget; +class TQLayoutItem; + +class KGreeterPluginHandler { +public: + /* keep in sync with V_IS_* */ + enum { IsSecret = 1, IsUser = 2, IsPassword = 4, IsOldPassword = 8, + IsNewPassword = 16 }; + /** + * Reply to textPrompt(). + * @param text text to return to core; null to abort auth cycle + * @param tag zero or one of Is* + */ + virtual void gplugReturnText( const char *text, int tag ) = 0; + /** + * Reply to binaryPrompt(). + * @param data data in pam_client format to return to the core; + * null to abort auth cycle + */ + virtual void gplugReturnBinary( const char *data ) = 0; + /** + * Tell the greeter who is logging in. + * Call this preferably before gplugStart, as otherwise the .dmrc + * load will be delayed. Don't call at all if your plugin doesn't + * have the Local flag set. Call only for internally generated + * user changes. + * @param user the user logging in + */ + virtual void gplugSetUser( const TQString &user ) = 0; + /** + * Start processing. + */ + virtual void gplugStart() = 0; + /** + * Plugins that expect user input from a different device than the mouse or + * keyboard must call this when user activity is detected to prevent the + * greeter from resetting/going away. Events should be compressed to no + * more than ten per second; one every five seconds is actually enough. + * Events should be actual changes to the input fields, not random motion. + */ + virtual void gplugActivity() = 0; + /** + * Show a message box on behalf of the talker. + * @param type message severity + * @param text message text + */ + virtual void gplugMsgBox( TQMessageBox::Icon type, const TQString &text ) = 0; +}; + +/** + * Abstract base class for conversation plugins ("talkers") to be used with + * TDM, kdesktop_lock, etc. + * The authentication method used by a particular instance of a plugin + * may be configurable, but the instance must handle exactly one method, + * i.e., info->method must be determined at the latest at init() time. + */ +class KGreeterPlugin { +public: + KGreeterPlugin( KGreeterPluginHandler *h ) : handler( h ) {} + virtual ~KGreeterPlugin() {} + + /** + * Variations of the talker: + * - Authenticate: authentication + * - AuthChAuthTok: authentication and password change + * - ChAuthTok: password change + */ + enum Function { Authenticate, AuthChAuthTok, ChAuthTok }; + + /** + * Contexts the talker can be used in: + * - Login: tdm login dialog + * - Shutdown: tdm shutdown dialog + * - Unlock: tdm unlock dialog (TODO) + * - ChangeTok: tdm password change dialog (TODO) + * - ExUnlock: kdesktop_lock unlock dialog + * - ExChangeTok: kdepasswd password change dialog (TODO) + * + * The Ex* contexts exist within a running session; the talker must know + * how to obtain the currently logged in user (+ domain/realm, etc.) + * itself (i.e., fixedEntity will be null). The non-Ex variants will have + * a fixedEntity passed in. + */ + enum Context { Login, Shutdown, Unlock, ChangeTok, + ExUnlock, ExChangeTok }; + + /** + * Provide the talker with a list of selectable users. This can be used + * for autocompletion, etc. + * Will be called only when not running. + * @param users the users to load. + */ + virtual void loadUsers( const TQStringList &users ) = 0; + + /** + * Preload the talker with an (opaque to the greeter) entity. + * Will be called only when not running. + * @param entity the entity to preload the talker with. That + * will usually be something like "user" or "user@domain". + * @param field the sub-widget (probably line edit) to put the cursor into. + * If -1, preselect the user for timed login. This means pre-filling + * the password field with anything, disabling it, and placing the + * cursor in the user name field. + */ + virtual void presetEntity( const TQString &entity, int field ) = 0; + + /** + * Obtain the actually logged in entity. + * Will be called only after succeeded() was called. + */ + virtual TQString getEntity() const = 0; + + /** + * "Push" a user into the talker. That can be a click into the user list + * or successful authentication without the talker calling gplugSetUser. + * Will be called only when running. + * @param user the user to set. Note that this is a UNIX login, not a + * canonical entity + */ + virtual void setUser( const TQString &user ) = 0; + + /** + * "Push" a password into the talker. + * @param pass the password to set. + */ + virtual void setPassword( const TQString &pass ) = 0; + + /** + * En-/disable any widgets contained in the talker. + * Will be called only when not running. + * @param on the state to set + */ + virtual void setEnabled( bool on ) = 0; + + /** + * Called when a message from the authentication backend arrives. + * @param message the message received from the backend + * @param error if true, @p message is an error message, otherwise it's + * an informational message + * @return true means that the talker already handled the message, false + * that the greeter should display it in a message box + * + * FIXME: Filtering a message usually means that the backend issued a + * prompt and obtains the authentication data itself. However, in that + * state the backend is unresponsive, e.g., no shutdown is possible. + * The frontend could send the backend a signal, but the "escape path" + * within the backend is unclear (PAM won't like simply longjmp()ing + * out of it). + */ + virtual bool textMessage( const char *message, bool error ) = 0; + + /** + * Prompt the user for data. Reply by calling handler->gplugReturnText(). + * @param propmt 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 + * visually obscures the user's input. + * @param nonBlocking if true, report whatever is already available, + * otherwise wait for user input. + */ + virtual void textPrompt( const char *prompt, bool echo, bool nonBlocking ) = 0; + + /** + * Request binary authentication data from the talker. Reply by calling + * handler->gplugReturnBinary(). + * @param prompt prompt in pam_client format + * @param nonBlocking if true, report whatever is already available, + * otherwise wait for user input. + * @return always true for now + * + * TODO: + * @return if true, the prompt was handled by the talker, otherwise the + * handler has to use libpam_client to obtain the authentication data. + * In that state the talker still can abort the data fetch by + * gplugReturn()ing a null array. When the data was obtained, another + * binaryPrompt with a null prompt will be issued. + */ + virtual bool binaryPrompt( const char *prompt, bool nonBlocking ) = 0; + + /** + * This can either + * - Start a processing cycle. Will be called only when not running. + * - Restart authTok cycle - will be called while running and implies + * revive(). PAM is a bit too clever, so we need this. + * In any case the talker is running afterwards. + */ + virtual void start() = 0; + + /** + * Request to suspend the auth. Make sure that a second talker of any + * type will be able to operate while this one is suspended (no busy + * device nodes, etc.). + * Will be called only if running within Login context. (Actually it + * won't be called at all, but be prepared.) + */ + virtual void suspend() = 0; + + /** + * Request to resume the auth from the point it was suspended at. + * Will be called only when suspended. + */ + virtual void resume() = 0; + + /** + * The "login" button was pressed in the greeter. + * This might call gplugReturn* or gplugStart. + * Will be called only when running. + */ + virtual void next() = 0; + + /** + * Abort auth cycle. Note that this should _not_ clear out already + * entered auth tokens if they are still on the screen. + * Will be called only when running and stops it. + */ + virtual void abort() = 0; + + /** + * Indicate successful end of the current phase. + * This is more or less a request to disable editable widgets + * responsible for the that phase. + * There will be no further attempt to enter that phase until the + * widget is destroyed. + * Will be called only when running and stops it. + */ + virtual void succeeded() = 0; + + /** + * Indicate unsuccessful end of the current phase. + * This is mostly a request to disable all editable widgets. + * The widget will be treated as dead until revive() is called. + * Will be called only when running and stops it. + */ + virtual void failed() = 0; + + /** + * Prepare retrying the previously failed phase. + * This is mostly a request to re-enable all editable widgets failed() + * disabled previously, clear the probably incorrect authentication tokens + * and to set the input focus appropriately. + * Will be called only after failed() (possibly with clear() in between), + * or after presetEntity() with field -1. + */ + virtual void revive() = 0; + + /** + * Clear any edit widgets, particularily anything set by setUser. + * Will be called only when not running. + */ + virtual void clear() = 0; + + /** + * Obtain the TQLayoutItem containg the widget(s) to actually handle the + * conversation. See TQLayout and TQWidgetItem for possible implementations. + */ + TQLayoutItem *getLayoutItem() const { return layoutItem; } + +protected: + KGreeterPluginHandler *handler; + TQLayoutItem *layoutItem; +}; + +struct KDE_EXPORT kgreeterplugin_info { + /** + * Human readable name of this plugin (should be a little more + * informative than just the libary name). Must be I18N_NOOP()ed. + */ + const char *name; + + /** + * The authentication method to use - the meaning is up to the backend, + * but will usually be related to the PAM service. + */ + const char *method; + + /** + * Capabilities. + */ + enum { + /** + * All users exist on the local system permanently (will be listed + * by getpwent()); an entity corresponds to a UNIX user. + */ + Local = 1, + /** + * The entities consist of multiple fields. + * PluginOptions/.FocusField is used instead of FocusPasswd. + */ + Fielded = 2, + /** + * An entity can be preset, the talker has a widget where a user can + * be selected explicitly. If the method is "classic", timed login + * is possible, too. + * This also means that setUser/gplugSetUser can be used and a + * userlist can be shown at all - provided Local is set as well. + */ + Presettable = 4 + }; + + /* + * Capability flags. + */ + int flags; + + /** + * Call after loading the plugin. + * + * @param method if non-empty and the plugin is unable to handle that + * method, return false. If the plugin has a constant method defined + * above, it can ignore this parameter. + * @param getConf can be used to obtain configuration items from the + * greeter; you have to pass it the @p ctx pointer. + * The only predefined key (in TDM) is "EchoMode", which is an int + * (in fact, KPasswordEdit::EchoModes). + * Other keys are obtained from the PluginOptions option; see tdmrc + * for details. + * If the key is unknown, dflt is returned. + * @param ctx context pointer for @p getConf + * @return if false, unload the plugin again (don't call done() first) + */ + bool (*init)( const TQString &method, + TQVariant (*getConf)( void *ctx, const char *key, + const TQVariant &dflt ), + void *ctx ); + + /** + * Call before unloading the plugin. + * This pointer can be null. + */ + void (*done)( void ); + + /** + * Factory method to create an instance of the plugin. + * Note that multiple instances can exist at one time, but only + * one of them is active at any moment (the others would be suspended + * or not running at all). + * @param handler the object offering the necessary callbacks + * @param parent parent widget + * @param predecessor the focus widget before the conversation widget + * @param fixedEntity see below + * @param func see below + * @param ctx see below + * @return an instance of this conversation plugin + * + * Valid combinations of Function and Context: + * - Authenticate:Login - init + * - Authenticate:Shutdown - init, for now "root" is passed as fixedEntitiy + * and it is not supposed to be displayed. Plugins with Local not set + * might have to conjure something up to make getEntity() return a + * canonical entitiy. FIXME: don't restrict shutdown to root. + * - AuthChAuthTok:Login, AuthChAuthTok:Shutdown - cont/cont, + * only relevant for classic method (as it is relevant only for password- + * less logins, which always use classic). The login should not be shown - + * it is known to the user already; the backend won't ask for it, either. + * - ChAuthTok:Login & ChAuthTok:Shutdown - cont + * - Authenticate:Unlock & Authenticate:ExUnlock - init, + * AuthChAuthTok:ChangeTok & AuthChAuthTok:ExChangeTok - init/cont, + * display fixedEntity as labels. The backend does not ask for the UNIX + * login, as it already knows it - but it will ask for all components of + * the entity if it is no UNIX login. + * + * "init" means that the plugin is supposed to call gplugStart, "cont" + * that the backend is already in a cycle of the method the plugin was + * initialized with. + */ + KGreeterPlugin *(*create)( KGreeterPluginHandler *handler, + KdmThemer *themer, + TQWidget *parent, TQWidget *predecessor, + const TQString &fixedEntity, + KGreeterPlugin::Function func, + KGreeterPlugin::Context ctx ); +}; + +#endif diff --git a/tdmlib/tdmtsak.cpp b/tdmlib/tdmtsak.cpp new file mode 100644 index 000000000..18acd05d2 --- /dev/null +++ b/tdmlib/tdmtsak.cpp @@ -0,0 +1,180 @@ +/* + This file is part of the TDE project + Copyright (C) 2011 Timothy Pearson + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "tdmtsak.h" + +#include + +#define FIFO_FILE "/tmp/ksocket-global/tsak" + +TQString exec(const char * cmd) { + FILE* pipe = popen(cmd, "r"); + if (!pipe) return "ERROR"; + char buffer[128]; + TQString result = ""; + while(!feof(pipe)) { + if(fgets(buffer, 128, pipe) != NULL) + result += buffer; + } + pclose(pipe); + return result; +} + +bool is_vt_local() { + const char * currentDisplay; + currentDisplay = getenv ("DISPLAY"); + if (currentDisplay == NULL) { + return false; + } + else { + TQString cvtName = ""; + TQString output = exec("tdmctl list"); + TQStringList sessionList = TQStringList::split('\t', output, false); + // See if the current session is local + for ( TQStringList::Iterator it = sessionList.begin(); it != sessionList.end(); ++it ) { + TQStringList sessionInfoList = TQStringList::split(',', *it, true); + if ((*(sessionInfoList.at(0))).startsWith(":")) { + if (TQString(currentDisplay).startsWith(*(sessionInfoList.at(0)))) { + return true; + } + } + } + // Not local + return false; + } +} + +bool is_vt_active() { + const char * currentDisplay; + currentDisplay = getenv ("DISPLAY"); + if (currentDisplay == NULL) { + return true; + } + else { + TQString cvtName = ""; + TQString output = exec("tdmctl list"); + TQString curConsole = exec("fgconsole"); + bool intFound; + int curConsoleNum = curConsole.toInt(&intFound); + if (intFound == false) { + return true; + } + curConsole = TQString("vt%1").arg(curConsoleNum);; + TQStringList sessionList = TQStringList::split('\t', output, false); + for ( TQStringList::Iterator it = sessionList.begin(); it != sessionList.end(); ++it ) { + TQStringList sessionInfoList = TQStringList::split(',', *it, true); + if ((*(sessionInfoList.at(0))).startsWith(":")) { + if ((*(sessionInfoList.at(1))) == TQString(curConsole)) { + cvtName = (*(sessionInfoList.at(0))); + } + } + } + if (cvtName != "") { + if (TQString(currentDisplay).startsWith(cvtName)) { + return true; + } + else { + return false; + } + } + else { + // See if the current session is local + // If it is, then the VT is not currently active and the SAK must be requested later when it is active + for ( TQStringList::Iterator it = sessionList.begin(); it != sessionList.end(); ++it ) { + TQStringList sessionInfoList = TQStringList::split(',', *it, true); + if ((*(sessionInfoList.at(0))).startsWith(":")) { + if (TQString(currentDisplay).startsWith(*(sessionInfoList.at(0)))) { + return false; + } + } + } + // Hmm, not local + // Do not reject the SAK + return true; + } + } +} + +int main (int argc, char *argv[]) +{ + int mPipe_fd; + char readbuf[128]; + int numread; + + int verifier_result = tde_sak_verify_calling_process(); + + bool isdm = false; + if (argc == 2) { + if (strcmp(argv[1], "dm") == 0) { + isdm = true; + } + } + + if (!isdm) { + // Verify that the session is local + // Remote sessions cannot press the SAK for obvious reasons + if (!is_vt_local()) { + return 6; // SAK not available + } + } + + if (verifier_result == 0) { + // OK, the calling process is authorized to retrieve SAK data + // First, flush the buffer + mPipe_fd = open(FIFO_FILE, O_RDONLY | O_NONBLOCK); + numread = 1; + while (numread > 0) { + numread = read(mPipe_fd, readbuf, 6); + } + close(mPipe_fd); + // Now wait for SAK press + mPipe_fd = open(FIFO_FILE, O_RDONLY); + while (mPipe_fd > -1) { + numread = read(mPipe_fd, readbuf, 6); + readbuf[numread] = 0; + readbuf[127] = 0; + if (strcmp(readbuf, "SAK\n\r") == 0) { + close(mPipe_fd); + if (is_vt_active()) { + return 0; + } + else { + usleep(100); + // Flush the buffer + mPipe_fd = open(FIFO_FILE, O_RDONLY | O_NONBLOCK); + numread = 1; + while (numread > 0) { + numread = read(mPipe_fd, readbuf, 6); + } + close(mPipe_fd); + mPipe_fd = open(FIFO_FILE, O_RDONLY); + } + } + else { + usleep(100); + } + } + close(mPipe_fd); + return 6; + } + else { + return verifier_result; + } +} \ No newline at end of file diff --git a/tdmlib/tdmtsak.h b/tdmlib/tdmtsak.h new file mode 100644 index 000000000..1987a8218 --- /dev/null +++ b/tdmlib/tdmtsak.h @@ -0,0 +1,144 @@ +/* + This file is part of the TDE project + Copyright (C) 2011 Timothy Pearson + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "config.h" + +// #define DEBUG + +inline int tde_sak_verify_calling_process() +{ + bool authorized = false; + + // Root always has access to everything... + if (getuid() == 0) { + return 0; + } + + pid_t parentproc = getppid(); +#ifdef DEBUG + printf("Parent pid is: %d\n\r", parentproc); +#endif + + char parentexecutable[8192]; + TQString procparent = TQString("/proc/%1/exe").arg(parentproc); + int chars = readlink(procparent.ascii(), parentexecutable, sizeof(parentexecutable)); + parentexecutable[chars] = 0; + parentexecutable[8191] = 0; + procparent = parentexecutable; +#ifdef DEBUG + printf("Parent executable name and full path is: %s\n\r", procparent.ascii()); +#endif + + TQString tdeBinaryPath = TQString(KDE_BINDIR "/"); +#ifdef DEBUG + printf("The TDE binary path is: %s\n\r", tdeBinaryPath.ascii()); +#endif + + if (!procparent.startsWith(tdeBinaryPath)) { + printf("Unauthorized path detected in calling process\n\r"); + return 2; + } + else { + procparent = procparent.mid(tdeBinaryPath.length()); +#ifdef DEBUG + printf("Parent executable name is: %s\n\r", procparent.ascii()); +#endif + if ((procparent == "kdesktop") || (procparent == "kdesktop_lock") || (procparent == "tdm")) { + authorized = true; + } + else if (procparent == "tdeinit") { + printf("tdeinit detected\n\r"); + // A bit more digging is needed to see if this is an authorized process or not + // Get the tdeinit command + char tdeinitcmdline[8192]; + FILE *fp = fopen(TQString("/proc/%1/cmdline").arg(parentproc).ascii(),"r"); + if (fp != NULL) { + if (fgets (tdeinitcmdline, 8192, fp) != NULL) + fclose (fp); + } + tdeinitcmdline[8191] = 0; + TQString tdeinitCommand = tdeinitcmdline; + + // Also get the environment, specifically the path + TQString tdeinitEnvironment; + char tdeinitenviron[8192]; + fp = fopen(TQString("/proc/%1/environ").arg(parentproc).ascii(),"r"); + if (fp != NULL) { + int c; + int pos = 0; + do { + c = fgetc(fp); + tdeinitenviron[pos] = c; + pos++; + if (c == 0) { + TQString curEnvLine = tdeinitenviron; + if (curEnvLine.startsWith("PATH=")) { + tdeinitEnvironment = curEnvLine.mid(5); + } + pos = 0; + } + } while ((c != EOF) && (pos < 8192)); + fclose (fp); + } + tdeinitenviron[8191] = 0; + +#ifdef DEBUG + printf("Called executable name is: %s\n\r", tdeinitCommand.ascii()); + printf("Environment is: %s\n\r", tdeinitEnvironment.ascii()); +#endif + + if ((tdeinitCommand == "kdesktop [tdeinit]") && (tdeinitEnvironment.startsWith(KDE_BINDIR))) { + authorized = true; + } + else { + return 4; + } + } + else { + printf("Unauthorized calling process detected\n\r"); + return 3; + } + + if (authorized == true) { + return 0; + } + } + + return 5; +} + +#undef DEBUG \ No newline at end of file -- cgit v1.2.3