• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KNewStuff

security.cpp

Go to the documentation of this file.
00001 /*
00002     This file is part of KNewStuff2.
00003     Copyright (c) 2004, 2005 Andras Mantia <amantia@kde.org>
00004     Copyright (c) 2007 Josef Spillner <spillner@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
00020 */
00021 
00022 //app includes
00023 #include "security.h"
00024 
00025 //qt includes
00026 #include <QtCore/QFile>
00027 #include <QtCore/QFileInfo>
00028 #include <QtCore/QStringList>
00029 #include <QtCore/QTextIStream>
00030 #include <QtCore/QTimer>
00031 
00032 //kde includes
00033 #include <kdebug.h>
00034 #include <kinputdialog.h>
00035 #include <klocale.h>
00036 #include <kcodecs.h>
00037 #include <kmessagebox.h>
00038 #include <kpassworddialog.h>
00039 #include <kprocess.h>
00040 
00041 using namespace KNS;
00042 
00043 Security::Security()
00044 {
00045     m_keysRead = false;
00046     m_gpgRunning = false;
00047     readKeys();
00048     readSecretKeys();
00049 }
00050 
00051 
00052 Security::~Security()
00053 {
00054 }
00055 
00056 void Security::readKeys()
00057 {
00058     if (m_gpgRunning) {
00059         QTimer::singleShot(5, this, SLOT(readKeys()));
00060         return;
00061     }
00062     m_runMode = List;
00063     m_keys.clear();
00064     m_process = new KProcess();
00065     *m_process << "gpg"
00066     << "--no-secmem-warning"
00067     << "--no-tty"
00068     << "--with-colon"
00069     << "--list-keys";
00070     connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
00071             this, SLOT(slotFinished(int, QProcess::ExitStatus)));
00072     connect(m_process, SIGNAL(readyReadStandardOutput()),
00073             this, SLOT(slotReadyReadStandardOutput()));
00074     m_process->start();
00075     if (!m_process->waitForStarted()) {
00076         KMessageBox::error(0L, i18n("<qt>Cannot start <i>gpg</i> and retrieve the available keys. Make sure that <i>gpg</i> is installed, otherwise verification of downloaded resources will not be possible.</qt>"));
00077         delete m_process;
00078         m_process = 0;
00079     } else
00080         m_gpgRunning = true;
00081 }
00082 
00083 void Security::readSecretKeys()
00084 {
00085     if (m_gpgRunning) {
00086         QTimer::singleShot(5, this, SLOT(readSecretKeys()));
00087         return;
00088     }
00089     m_runMode = ListSecret;
00090     m_process = new KProcess();
00091     *m_process << "gpg"
00092     << "--no-secmem-warning"
00093     << "--no-tty"
00094     << "--with-colon"
00095     << "--list-secret-keys";
00096     connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
00097             this, SLOT(slotFinished(int, QProcess::ExitStatus)));
00098     connect(m_process, SIGNAL(readyReadStandardOutput()),
00099             this, SLOT(slotReadyReadStandardOutput()));
00100     m_process->start();
00101     if (!m_process->waitForStarted()) {
00102         delete m_process;
00103         m_process = 0;
00104     } else
00105         m_gpgRunning = true;
00106 }
00107 
00108 void Security::slotFinished(int exitCode, QProcess::ExitStatus exitStatus)
00109 {
00110     if (exitStatus != QProcess::NormalExit) {
00111         m_gpgRunning = false;
00112         delete m_process;
00113         m_process = 0;
00114         return;
00115     }
00116     switch (m_runMode) {
00117     case ListSecret:
00118         m_keysRead = true;
00119         break;
00120     case Verify: emit validityResult(m_result);
00121         break;
00122     case Sign:   emit fileSigned(m_result);
00123         break;
00124 
00125     }
00126     m_gpgRunning = false;
00127     delete m_process;
00128     m_process = 0;
00129 
00130     Q_UNUSED(exitCode);
00131 }
00132 
00133 void Security::slotReadyReadStandardOutput()
00134 {
00135     QString data;
00136     while (m_process->canReadLine()) {
00137         data = QString::fromLocal8Bit(m_process->readLine());
00138         switch (m_runMode) {
00139         case List:
00140         case ListSecret:
00141             if (data.startsWith("pub") || data.startsWith("sec")) {
00142                 KeyStruct key;
00143                 if (data.startsWith("pub"))
00144                     key.secret = false;
00145                 else
00146                     key.secret = true;
00147                 QStringList line = data.split(":", QString::KeepEmptyParts);
00148                 key.id = line[4];
00149                 QString shortId = key.id.right(8);
00150                 QString trustStr = line[1];
00151                 key.trusted = false;
00152                 if (trustStr == "u" || trustStr == "f")
00153                     key.trusted = true;
00154                 data = line[9];
00155                 key.mail = data.section('<', -1, -1);
00156                 key.mail.truncate(key.mail.length() - 1);
00157                 key.name = data.section('<', 0, 0);
00158                 if (key.name.contains("("))
00159                     key.name = key.name.section('(', 0, 0);
00160                 m_keys[shortId] = key;
00161             }
00162             break;
00163         case Verify:
00164             data = data.section("]", 1, -1).trimmed();
00165             if (data.startsWith("GOODSIG")) {
00166                 m_result &= SIGNED_BAD_CLEAR;
00167                 m_result |= SIGNED_OK;
00168                 QString id = data.section(" ", 1 , 1).right(8);
00169                 if (!m_keys.contains(id)) {
00170                     m_result |= UNKNOWN;
00171                 } else {
00172                     m_signatureKey = m_keys[id];
00173                 }
00174             } else
00175                 if (data.startsWith("NO_PUBKEY")) {
00176                     m_result &= SIGNED_BAD_CLEAR;
00177                     m_result |= UNKNOWN;
00178                 } else
00179                     if (data.startsWith("BADSIG")) {
00180                         m_result |= SIGNED_BAD;
00181                         QString id = data.section(" ", 1 , 1).right(8);
00182                         if (!m_keys.contains(id)) {
00183                             m_result |= UNKNOWN;
00184                         } else {
00185                             m_signatureKey = m_keys[id];
00186                         }
00187                     } else
00188                         if (data.startsWith("TRUST_ULTIMATE")) {
00189                             m_result &= SIGNED_BAD_CLEAR;
00190                             m_result |= TRUSTED;
00191                         }
00192             break;
00193 
00194         case Sign:
00195             if (data.contains("passphrase.enter")) {
00196                 KeyStruct key = m_keys[m_secretKey];
00197                 KPasswordDialog dlg;
00198                 dlg.setPrompt(i18n("<qt>Enter passphrase for key <b>0x%1</b>, belonging to<br /><i>%2&lt;%3&gt;</i><br />:</qt>", m_secretKey, key.name, key.mail));
00199                 if (dlg.exec()) {
00200                     m_process->write(dlg.password().toLocal8Bit() + '\n');
00201                 } else {
00202                     m_result |= BAD_PASSPHRASE;
00203                     m_process->kill();
00204                     return;
00205                 }
00206             } else
00207                 if (data.contains("BAD_PASSPHRASE")) {
00208                     m_result |= BAD_PASSPHRASE;
00209                 }
00210             break;
00211         }
00212     }
00213 }
00214 
00215 void Security::checkValidity(const QString& filename)
00216 {
00217     m_fileName = filename;
00218     slotCheckValidity();
00219 }
00220 
00221 void Security::slotCheckValidity()
00222 {
00223     if (!m_keysRead || m_gpgRunning) {
00224         QTimer::singleShot(5, this, SLOT(slotCheckValidity()));
00225         return;
00226     }
00227     if (m_keys.count() == 0) {
00228         emit validityResult(-1);
00229         return;
00230     }
00231 
00232     m_result = 0;
00233     m_runMode = Verify;
00234     QFileInfo f(m_fileName);
00235     //check the MD5 sum
00236     QString md5sum;
00237     const char* c = "";
00238     KMD5 context(c);
00239     QFile file(m_fileName);
00240     if (file.open(QIODevice::ReadOnly)) {
00241         context.reset();
00242         context.update(file);
00243         md5sum = context.hexDigest();
00244         file.close();
00245     }
00246     file.setFileName(f.path() + "/md5sum");
00247     if (file.open(QIODevice::ReadOnly)) {
00248         QByteArray md5sum_file;
00249         file.readLine(md5sum_file.data(), 50);
00250         if (!md5sum_file.isEmpty() && QString(md5sum_file).startsWith(md5sum))
00251             m_result |= MD5_OK;
00252         file.close();
00253     }
00254     m_result |= SIGNED_BAD;
00255     m_signatureKey.id = "";
00256     m_signatureKey.name = "";
00257     m_signatureKey.mail = "";
00258     m_signatureKey.trusted = false;
00259 
00260     //verify the signature
00261     m_process = new KProcess();
00262     *m_process << "gpg"
00263     << "--no-secmem-warning"
00264     << "--status-fd=2"
00265     << "--command-fd=0"
00266     << "--verify"
00267     << f.path() + "/signature"
00268     << m_fileName;
00269     connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
00270             this, SLOT(slotFinished(int, QProcess::ExitStatus)));
00271     connect(m_process, SIGNAL(readyReadStandardOutput()),
00272             this, SLOT(slotReadyReadStandardOutput()));
00273     m_process->start();
00274     if (m_process->waitForStarted())
00275         m_gpgRunning = true;
00276     else {
00277         KMessageBox::error(0L, i18n("<qt>Cannot start <i>gpg</i> and check the validity of the file. Make sure that <i>gpg</i> is installed, otherwise verification of downloaded resources will not be possible.</qt>"));
00278         emit validityResult(0);
00279         delete m_process;
00280         m_process = 0;
00281     }
00282 }
00283 
00284 void Security::signFile(const QString &fileName)
00285 {
00286     m_fileName = fileName;
00287     slotSignFile();
00288 }
00289 
00290 void Security::slotSignFile()
00291 {
00292     if (!m_keysRead || m_gpgRunning) {
00293         QTimer::singleShot(5, this, SLOT(slotSignFile()));
00294         return;
00295     }
00296 
00297     QStringList secretKeys;
00298     for (QMap<QString, KeyStruct>::Iterator it = m_keys.begin(); it != m_keys.end(); ++it) {
00299         if (it.value().secret)
00300             secretKeys.append(it.key());
00301     }
00302 
00303     if (secretKeys.count() == 0) {
00304         emit fileSigned(-1);
00305         return;
00306     }
00307 
00308     m_result = 0;
00309     QFileInfo f(m_fileName);
00310 
00311     //create the MD5 sum
00312     QString md5sum;
00313     const char* c = "";
00314     KMD5 context(c);
00315     QFile file(m_fileName);
00316     if (file.open(QIODevice::ReadOnly)) {
00317         context.reset();
00318         context.update(file);
00319         md5sum = context.hexDigest();
00320         file.close();
00321     }
00322     file.setFileName(f.path() + "/md5sum");
00323     if (file.open(QIODevice::WriteOnly)) {
00324         QTextStream stream(&file);
00325         stream << md5sum;
00326         m_result |= MD5_OK;
00327         file.close();
00328     }
00329 
00330     if (secretKeys.count() > 1) {
00331         bool ok;
00332         secretKeys = KInputDialog::getItemList(i18n("Select Signing Key"), i18n("Key used for signing:"), secretKeys, QStringList(secretKeys[0]), false, &ok);
00333         if (ok)
00334             m_secretKey = secretKeys[0];
00335         else {
00336             emit fileSigned(0);
00337             return;
00338         }
00339     } else
00340         m_secretKey = secretKeys[0];
00341 
00342     //verify the signature
00343     m_process = new KProcess();
00344     *m_process << "gpg"
00345     << "--no-secmem-warning"
00346     << "--status-fd=2"
00347     << "--command-fd=0"
00348     << "--no-tty"
00349     << "--detach-sign"
00350     << "-u"
00351     << m_secretKey
00352     << "-o"
00353     << f.path() + "/signature"
00354     << m_fileName;
00355     connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
00356             this, SLOT(slotFinished(int, QProcess::ExitStatus)));
00357     connect(m_process, SIGNAL(readyReadStandardOutput()),
00358             this, SLOT(slotReadyReadStandardOutput()));
00359     m_runMode = Sign;
00360     m_process->start();
00361     if (m_process->waitForStarted())
00362         m_gpgRunning = true;
00363     else {
00364         KMessageBox::error(0L, i18n("<qt>Cannot start <i>gpg</i> and sign the file. Make sure that <i>gpg</i> is installed, otherwise signing of the resources will not be possible.</qt>"));
00365         emit fileSigned(0);
00366         delete m_process;
00367         m_process = 0;
00368     }
00369 }
00370 
00371 #include "security.moc"

KNewStuff

Skip menu "KNewStuff"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal