/*************************************************************************** * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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())); // Set up card monitoring TDEGenericDevice *hwdevice; TDEHardwareDevices *hwdevices = TDEGlobal::hardwareDevices(); TDEGenericHardwareList cardReaderList = hwdevices->listByDeviceClass(TDEGenericDeviceType::CryptographicCard); for (hwdevice = cardReaderList.first(); hwdevice; hwdevice = cardReaderList.next()) { TDECryptographicCardDevice* cdevice = static_cast(hwdevice); cdevice->enableCardMonitoring(true); } 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) { bool allow_card = false; TDEGenericDevice *hwdevice; TDEHardwareDevices *hwdevices = TDEGlobal::hardwareDevices(); TDEGenericHardwareList cardReaderList = hwdevices->listByDeviceClass(TDEGenericDeviceType::CryptographicCard); for (hwdevice = cardReaderList.first(); hwdevice; hwdevice = cardReaderList.next()) { TDECryptographicCardDevice* cdevice = static_cast(hwdevice); TQString login_name = TQString::null; X509CertificatePtrList certList = cdevice->cardX509Certificates(); if (certList.count() > 0) { KSSLCertificate* card_cert = NULL; card_cert = KSSLCertificate::fromX509(certList[0]); TQStringList cert_subject_parts = TQStringList::split("/", card_cert->getSubject(), false); for (TQStringList::Iterator it = cert_subject_parts.begin(); it != cert_subject_parts.end(); ++it ) { TQString lcpart = (*it).lower(); if (lcpart.startsWith("cn=")) { login_name = lcpart.right(lcpart.length() - strlen("cn=")); } } delete card_cert; } if (login_name != "") { allow_card = true; break; } } 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, allow_card, 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("Failed to obtain ticket

%1").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("Failed to obtain service ticket

%1").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 + "
"; origString += i18n("Client: ") + ticket.clientPrincipal + "
"; origString += i18n("Encryption Type: ") + ticket.encryptionType + "
"; origString += i18n("Key Version: %1").arg(ticket.keyVersionNumber) + "
"; if (ticket.authenticationTime.isValid()) origString += i18n("Authenticated: ") + ticket.authenticationTime.toString() + "
"; if (ticket.validStartTime.isValid()) origString += i18n("Valid After: ") + ticket.validStartTime.toString() + "
"; if (ticket.validEndTime.isValid()) origString += i18n("Valid Before: ") + ticket.validEndTime.toString() + "
"; return origString; } void TopLevel::showTicketList() { int i; TQString listText = ""; 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("Kerberos Ticket %1").arg(i) + "
"; listText += addTicketInfo("", ticket); listText += "

"; i++; } } listText += ""; KMessageBox::information(this, listText, i18n("Kerberos Ticket Information"), TQString::null, KMessageBox::Notify); } void TopLevel::menuAction(int index) { if (index >= 0) { TQString listText = ""; KerberosTicketInfo ticket = m_ticketList[index]; listText += i18n("Kerberos Ticket %1").arg(index+1) + "
"; listText += addTicketInfo("", ticket); listText += "
"; 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("Failed to destroy ticket
%1

%2").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(); }