You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
450 lines
14 KiB
450 lines
14 KiB
/***************************************************************************
|
|
* 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();
|
|
}
|