/***************************************************************************
* Copyright ( C ) 2012 by Timothy Pearson *
* kb9vqf @ pearsoncomputing . net *
* *
* 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 . , *
* 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <stdlib.h>
# include <assert.h>
# include <sys/types.h>
# include <pwd.h>
# include <tqcheckbox.h>
# include <tqlayout.h>
# include <tqhbox.h>
# include <tqvbox.h>
# include <tqlineedit.h>
# include <tqpainter.h>
# include <tqtooltip.h>
# include <tqfile.h>
# include <tqcursor.h>
# include <tqpushbutton.h>
# include <tqgroupbox.h>
# include <tqheader.h>
# include <tqpixmap.h>
# include <tqbitmap.h>
# include <tdeconfig.h>
# include <khelpmenu.h>
# include <kiconloader.h>
# include <tdelocale.h>
# include <tdemessagebox.h>
# include <kpassivepopup.h>
# include <knotifyclient.h>
# include <knuminput.h>
# include <kseparator.h>
# include <tdepopupmenu.h>
# include <kdialogbase.h>
# include <tdeaction.h>
# include <knotifydialog.h>
# include <klineeditdlg.h>
# include <libtdeldap.h>
# include "configdlg.h"
# include "toplevel.h"
# include "toplevel.moc"
TopLevel : : TopLevel ( ) : KSystemTray ( ) , ticketWatch ( 0 ) , m_refreshTimer ( 0 ) , m_requestUpdateTimer ( 0 ) , notifyExpiryMinutes ( 0 )
{
setBackgroundMode ( X11ParentRelative ) ; // what for?
TDEConfig * config = kapp - > config ( ) ;
config - > setGroup ( " Kerberos " ) ;
getNewTGTAct = new TDEAction ( i18n ( " &Obtain New Ticket Granting Ticket " ) , " add_user " , 0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( getNewTGT ( ) ) , actionCollection ( ) , " getnewtgt " ) ;
getNewSTAct = new TDEAction ( i18n ( " &Obtain New Primary Service Ticket " ) , " add_user " , 0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( getNewServiceTicket ( ) ) , actionCollection ( ) , " getnewserviceticket " ) ;
getNewStandardSTAct = new TDEAction ( i18n ( " &Obtain Authenticated Service Ticket " ) , " add_user " , 0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( getNewServiceTicketWithExistingCreds ( ) ) , actionCollection ( ) , " getstandardserviceticket " ) ;
destroyAllAct = new TDEAction ( i18n ( " &Destroy All Tickets " ) , " delete_user " , 0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( destroyAllTickets ( ) ) , actionCollection ( ) , " destroyall " ) ;
confAct = new TDEAction ( i18n ( " &Configure... " ) , " configure " , 0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( config ( ) ) , actionCollection ( ) , " configure " ) ;
// create app menu (displayed on right-click)
menu = new TQPopupMenu ( ) ;
connect ( menu , TQT_SIGNAL ( activated ( int ) ) , this , TQT_SLOT ( menuAction ( int ) ) ) ;
KHelpMenu * help = new KHelpMenu ( this , TDEGlobal : : instance ( ) - > aboutData ( ) , false ) ;
TDEPopupMenu * helpMnu = help - > menu ( ) ;
menu - > insertSeparator ( ) ;
getNewTGTAct - > plug ( menu ) ;
getNewSTAct - > plug ( menu ) ;
getNewStandardSTAct - > plug ( menu ) ;
destroyAllAct - > plug ( menu ) ;
menu - > insertSeparator ( ) ;
confAct - > plug ( menu ) ;
menu - > insertItem ( SmallIcon ( " help " ) , i18n ( " &Help " ) , helpMnu ) ;
menu - > insertItem ( SmallIcon ( " system-log-out " ) , i18n ( " Quit " ) , kapp , TQT_SLOT ( quit ( ) ) ) ;
load ( ) ;
updateTicketList ( ) ;
setupTimers ( ) ;
}
/* slot: signal shutDown() from TDEApplication */
/* (not currently needed)
void TopLevel : : queryExit ( )
{
TDEConfig * config = kapp - > config ( ) ;
// config->sync();
}
*/
/** Destructor */
TopLevel : : ~ TopLevel ( )
{
if ( ticketWatch ) delete ticketWatch ;
if ( m_refreshTimer ) m_refreshTimer - > stop ( ) ;
delete menu ;
// FIXME: must delete more (like all the TQWidgets in config-window)?
}
void TopLevel : : load ( ) {
TDEConfig * config = TDEGlobal : : instance ( ) - > config ( ) ;
config - > setGroup ( NULL ) ;
autostart = config - > readBoolEntry ( " Autostart " , true ) ;
notifyExpiry = config - > readBoolEntry ( " notifyExpiry " , true ) ;
notifyExpiryMinutes = config - > readNumEntry ( " notifyExpiryMinutes " , 5 ) ;
}
void TopLevel : : save ( ) {
TDEConfig * config = TDEGlobal : : instance ( ) - > config ( ) ;
config - > setGroup ( NULL ) ;
config - > writeEntry ( " Autostart " , autostart ) ;
config - > writeEntry ( " notifyExpiry " , notifyExpiry ) ;
config - > writeEntry ( " notifyExpiryMinutes " , notifyExpiryMinutes ) ;
config - > sync ( ) ;
setupTimers ( ) ;
}
void TopLevel : : setupTimers ( ) {
// FIXME
// Better would be to call updateTicketList() notifyExpiryMinutes before first ticket expiration
// For now this will work, but less efficiently
if ( ! m_refreshTimer ) {
m_refreshTimer = new TQTimer ( this ) ;
connect ( m_refreshTimer , TQT_SIGNAL ( timeout ( ) ) , this , TQT_SLOT ( updateTicketList ( ) ) ) ;
m_refreshTimer - > start ( 10 * 1000 , false ) ;
}
if ( ! m_requestUpdateTimer ) {
m_requestUpdateTimer = new TQTimer ( this ) ;
connect ( m_requestUpdateTimer , TQT_SIGNAL ( timeout ( ) ) , this , TQT_SLOT ( updateTicketList ( ) ) ) ;
}
}
void TopLevel : : requestTicketListUpdate ( ) {
m_requestUpdateTimer - > start ( 0 , TRUE ) ;
}
void TopLevel : : updateTicketList ( ) {
m_ticketList = LDAPManager : : getKerberosTicketList ( TQString : : null , & m_ticketFile ) ;
m_ticketFile . replace ( " FILE: " , " " ) ;
if ( ! ticketWatch ) {
ticketWatch = new KDirWatch ( ) ;
connect ( ticketWatch , TQT_SIGNAL ( dirty ( const TQString & ) ) , this , TQT_SLOT ( requestTicketListUpdate ( ) ) ) ;
connect ( ticketWatch , TQT_SIGNAL ( created ( const TQString & ) ) , this , TQT_SLOT ( requestTicketListUpdate ( ) ) ) ;
connect ( ticketWatch , TQT_SIGNAL ( deleted ( const TQString & ) ) , this , TQT_SLOT ( requestTicketListUpdate ( ) ) ) ;
ticketWatch - > addFile ( m_ticketFile ) ;
ticketWatch - > startScan ( ) ;
}
else {
ticketWatch - > removeFile ( m_ticketFile ) ;
ticketWatch - > addFile ( m_ticketFile ) ;
ticketWatch - > startScan ( ) ;
}
if ( m_ticketList . count ( ) > 0 ) {
getNewStandardSTAct - > setEnabled ( true ) ;
destroyAllAct - > setEnabled ( true ) ;
}
else {
getNewStandardSTAct - > setEnabled ( false ) ;
destroyAllAct - > setEnabled ( false ) ;
}
repaint ( ) ;
}
void TopLevel : : updateMenu ( ) {
// First, remove all current ticket entries from the menu; these can be identified by their positive id
while ( menu - > idAt ( 0 ) > = 0 ) {
menu - > removeItemAt ( 0 ) ;
}
// Add the new ticket entries to the top of the menu
int id = 0 ;
int index = 0 ;
if ( m_ticketList . count ( ) < 1 ) {
menu - > insertItem ( i18n ( " No Kerberos Tickets Available " ) , id + + , index + + ) ;
menu - > setItemEnabled ( 0 , false ) ;
}
else {
KerberosTicketInfoList : : Iterator it ;
for ( it = m_ticketList . begin ( ) ; it ! = m_ticketList . end ( ) ; + + it ) {
KerberosTicketInfo ticket = * it ;
TQDateTime now = TQDateTime : : currentDateTime ( ) ;
TQString label = ticket . serverPrincipal ;
if ( ticket . validEndTime > now ) {
label = label + i18n ( " (Active) " ) ;
}
else {
label = label + i18n ( " (Expired) " ) ;
}
menu - > insertItem ( label , id + + , index + + ) ;
}
}
}
void TopLevel : : getNewTicket ( bool requestServiceTicket ) {
LDAPCredentials credentials ;
if ( m_ticketList . count ( ) > 0 ) {
TQStringList princParts = TQStringList : : split ( " @ " , m_ticketList [ 0 ] . cachePrincipal ) ;
credentials . username = princParts [ 0 ] ;
credentials . realm = princParts [ 1 ] ;
}
else {
struct passwd * pwd = getpwuid ( geteuid ( ) ) ;
if ( pwd ) {
credentials . username = TQString ( pwd - > pw_name ) ;
}
}
int result = LDAPManager : : getKerberosPassword ( credentials , i18n ( " Please provide Kerberos credentials " ) , requestServiceTicket , this ) ;
if ( result = = KDialog : : Accepted ) {
TQString errorstring ;
TQString service ;
if ( requestServiceTicket ) {
service = credentials . service ;
}
if ( LDAPManager : : obtainKerberosTicket ( credentials , service , & errorstring ) ! = 0 ) {
KMessageBox : : error ( this , i18n ( " <qt>Failed to obtain ticket<p>%1</qt> " ) . arg ( errorstring ) , i18n ( " Failed to obtain Kerberos ticket " ) ) ;
}
}
updateTicketList ( ) ;
}
void TopLevel : : getNewTGT ( ) {
getNewTicket ( false ) ;
}
void TopLevel : : getNewServiceTicket ( ) {
getNewTicket ( true ) ;
}
void TopLevel : : getNewServiceTicketWithExistingCreds ( ) {
TQString errorstring ;
TQString service ;
bool ok ;
service = KLineEditDlg : : getText ( i18n ( " Enter the name of the Kerberos service principal you wish to obtain " ) , TQString : : null , & ok , this ) ;
if ( ok ) {
if ( LDAPManager : : obtainKerberosServiceTicket ( service , & errorstring ) ! = 0 ) {
KMessageBox : : error ( this , i18n ( " <qt>Failed to obtain service ticket<p>%1</qt> " ) . arg ( errorstring ) , i18n ( " Failed to obtain Kerberos service ticket " ) ) ;
}
}
}
void TopLevel : : destroyAllTickets ( ) {
if ( system ( " kdestroy --all " ) ! = 0 ) {
KMessageBox : : error ( this , i18n ( " Unable to destroy tickets! " ) , i18n ( " Internal Error " ) ) ;
}
updateTicketList ( ) ;
}
void TopLevel : : resizeEvent ( TQResizeEvent * )
{
activeTicketsPixmap = loadSizedIcon ( " kerberos_activetickets " , width ( ) ) ;
noTicketsPixmap = loadSizedIcon ( " kerberos_notickets " , width ( ) ) ;
expiredTicketsPixmap = loadSizedIcon ( " kerberos_expiredtickets " , width ( ) ) ;
partiallyExpiredTicketsPixmap = loadSizedIcon ( " kerberos_someexpiredtickets " , width ( ) ) ;
timerOverlayPixmap = loadSizedIcon ( " kerberos_timeroverlay " , width ( ) ) ;
warningOverlayPixmap = loadSizedIcon ( " kerberos_warningoverlay " , width ( ) ) ;
repaint ( ) ;
}
/** Handle mousePressEvent */
void TopLevel : : mousePressEvent ( TQMouseEvent * event ) {
if ( event - > button ( ) = = Qt : : LeftButton ) {
showTicketList ( ) ;
}
else if ( event - > button ( ) = = Qt : : RightButton ) {
updateMenu ( ) ;
menu - > popup ( TQCursor : : pos ( ) ) ;
}
else if ( event - > button ( ) = = MidButton ) {
// currently unused
}
}
/** Handle paintEvent (ie. animate icon) */
void TopLevel : : paintEvent ( TQPaintEvent * ) {
TQString baseToolTip = i18n ( " %1 Kerberos ticket(s) listed for principal %2 " ) . arg ( m_ticketList . count ( ) ) . arg ( m_ticketList [ 0 ] . cachePrincipal ) ;
bool has_tickets = false ;
bool tickets_expiring_soon = false ;
bool some_tickets_expired = false ;
bool all_tickets_expired = true ;
int expired_tickets = 0 ;
int expiring_tickets = 0 ;
KerberosTicketInfoList : : Iterator it ;
for ( it = m_ticketList . begin ( ) ; it ! = m_ticketList . end ( ) ; + + it ) {
KerberosTicketInfo ticket = * it ;
has_tickets = true ;
TQDateTime now = TQDateTime : : currentDateTime ( ) ;
if ( ticket . validEndTime > now ) {
all_tickets_expired = false ;
}
else {
expired_tickets + + ;
some_tickets_expired = true ;
}
if ( ( ticket . validEndTime > now ) & & ( ticket . validEndTime < now . addSecs ( notifyExpiryMinutes * 60 ) ) ) {
expiring_tickets + + ;
tickets_expiring_soon = true ;
}
}
if ( ! notifyExpiry ) tickets_expiring_soon = false ;
TQPainter p ( this ) ;
if ( has_tickets ) {
if ( all_tickets_expired ) {
p . drawPixmap ( 0 , 0 , expiredTicketsPixmap ) ;
p . drawPixmap ( 0 , 0 , warningOverlayPixmap ) ;
baseToolTip = baseToolTip + " \n " + i18n ( " All ticket(s) have expired " ) ;
}
else if ( some_tickets_expired ) {
p . drawPixmap ( 0 , 0 , partiallyExpiredTicketsPixmap ) ;
p . drawPixmap ( 0 , 0 , warningOverlayPixmap ) ;
baseToolTip = baseToolTip + " \n " + i18n ( " %1 ticket(s) have expired " ) . arg ( expired_tickets ) ;
}
else {
p . drawPixmap ( 0 , 0 , activeTicketsPixmap ) ;
if ( tickets_expiring_soon ) {
p . drawPixmap ( 0 , 0 , timerOverlayPixmap ) ;
baseToolTip = baseToolTip + " \n " + i18n ( " All ticket(s) are active \n %1 ticket(s) will expire shortly " ) . arg ( expiring_tickets ) ;
}
else {
baseToolTip = baseToolTip + " \n " + i18n ( " All ticket(s) are active " ) ;
}
}
}
else {
p . drawPixmap ( 0 , 0 , noTicketsPixmap ) ;
baseToolTip = i18n ( " No Kerberos tickets are available " ) ;
}
p . end ( ) ;
setToolTip ( baseToolTip ) ;
}
void TopLevel : : timerEvent ( TQTimerEvent * ) {
//
}
/** update ToolTip */
void TopLevel : : setToolTip ( const TQString & text , bool force ) {
// don't update if text hasn't changed
if ( lastTip = = text ) {
return ;
}
// don't remove Tooltip if (probably - can't know for sure?) currently showing
// FIXME: this isn't too nice: currently mouse must stay outside for >1s for update to occur
if ( force | | ! this - > hasMouse ( ) | | ( lastTip = = i18n ( " Kerberos Tickets Manager " ) ) ) {
lastTip = text ;
TQToolTip : : remove ( this ) ;
TQToolTip : : add ( this , text ) ;
}
}
TQString addTicketInfo ( TQString origString , KerberosTicketInfo ticket ) {
origString + = i18n ( " Server: " ) + ticket . serverPrincipal + " <br> " ;
origString + = i18n ( " Client: " ) + ticket . clientPrincipal + " <br> " ;
origString + = i18n ( " Encryption Type: " ) + ticket . encryptionType + " <br> " ;
origString + = i18n ( " Key Version: %1 " ) . arg ( ticket . keyVersionNumber ) + " <br> " ;
if ( ticket . authenticationTime . isValid ( ) ) origString + = i18n ( " Authenticated: " ) + ticket . authenticationTime . toString ( ) + " <br> " ;
if ( ticket . validStartTime . isValid ( ) ) origString + = i18n ( " Valid After: " ) + ticket . validStartTime . toString ( ) + " <br> " ;
if ( ticket . validEndTime . isValid ( ) ) origString + = i18n ( " Valid Before: " ) + ticket . validEndTime . toString ( ) + " <br> " ;
return origString ;
}
void TopLevel : : showTicketList ( ) {
int i ;
TQString listText = " <qt> " ;
updateTicketList ( ) ;
if ( m_ticketList . count ( ) < = 0 ) {
listText + = " No Kerberos tickets available " ;
}
else {
i = 1 ;
KerberosTicketInfoList : : Iterator it ;
for ( it = m_ticketList . begin ( ) ; it ! = m_ticketList . end ( ) ; + + it ) {
KerberosTicketInfo ticket = * it ;
listText + = i18n ( " <b>Kerberos Ticket %1</b> " ) . arg ( i ) + " <br> " ;
listText + = addTicketInfo ( " " , ticket ) ;
listText + = " <p> " ;
i + + ;
}
}
listText + = " </qt> " ;
KMessageBox : : information ( this , listText , i18n ( " Kerberos Ticket Information " ) , TQString : : null , KMessageBox : : Notify ) ;
}
void TopLevel : : menuAction ( int index ) {
if ( index > = 0 ) {
TQString listText = " <qt> " ;
KerberosTicketInfo ticket = m_ticketList [ index ] ;
listText + = i18n ( " <b>Kerberos Ticket %1</b> " ) . arg ( index + 1 ) + " <br> " ;
listText + = addTicketInfo ( " " , ticket ) ;
listText + = " </qt> " ;
if ( KMessageBox : : warningYesNo ( this , listText , i18n ( " Kerberos Ticket Information " ) , TQString ( " Destroy this Ticket " ) , TQString ( " Cancel " ) ) = = KMessageBox : : Yes ) {
TQString errorstring ;
if ( LDAPManager : : destroyKerberosTicket ( ticket . serverPrincipal , & errorstring ) ! = 0 ) {
KMessageBox : : error ( this , i18n ( " <qt>Failed to destroy ticket<br>%1<p>%2</qt> " ) . arg ( ticket . serverPrincipal ) . arg ( errorstring ) , i18n ( " Failed to destroy Kerberos ticket " ) ) ;
}
}
}
}
/* config-slot: "help" button clicked */
void TopLevel : : help ( ) {
kapp - > invokeHelp ( ) ;
}
void TopLevel : : config ( ) {
KTMConfigureDialog confdlg ( this , this ) ;
confdlg . exec ( ) ;
}