• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • 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 Lesser General Public
00008     License as published by the Free Software Foundation; either
00009     version 2.1 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     Lesser General Public License for more details.
00015 
00016     You should have received a copy of the GNU Lesser General Public
00017     License along with this library.  If not, see <http://www.gnu.org/licenses/>.
00018 */
00019 
00020 //app includes
00021 #include "security.h"
00022 
00023 //qt includes
00024 #include <QtCore/QFile>
00025 #include <QtCore/QFileInfo>
00026 #include <QtCore/QPointer>
00027 #include <QtCore/QStringList>
00028 #include <QtCore/QTextIStream>
00029 #include <QtCore/QTimer>
00030 
00031 //kde includes
00032 #include <kdebug.h>
00033 #include <kinputdialog.h>
00034 #include <klocale.h>
00035 #include <kcodecs.h>
00036 #include <kmessagebox.h>
00037 #include <kpassworddialog.h>
00038 #include <kprocess.h>
00039 
00040 using namespace KNS3;
00041 
00042 Security::Security()
00043 {
00044     m_keysRead = false;
00045     m_gpgRunning = false;
00046     readKeys();
00047     readSecretKeys();
00048 }
00049 
00050 
00051 Security::~Security()
00052 {
00053 }
00054 
00055 void Security::readKeys()
00056 {
00057     if (m_gpgRunning) {
00058         QTimer::singleShot(5, this, SLOT(readKeys()));
00059         return;
00060     }
00061     m_runMode = List;
00062     m_keys.clear();
00063     m_process = new KProcess();
00064     *m_process << "gpg2"
00065     << "--no-secmem-warning"
00066     << "--no-tty"
00067     << "--with-colon"
00068     << "--list-keys";
00069     connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
00070             this, SLOT(slotFinished(int, QProcess::ExitStatus)));
00071     connect(m_process, SIGNAL(readyReadStandardOutput()),
00072             this, SLOT(slotReadyReadStandardOutput()));
00073     m_process->start();
00074     if (!m_process->waitForStarted()) {
00075         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>"));
00076         delete m_process;
00077         m_process = 0;
00078     } else
00079         m_gpgRunning = true;
00080 }
00081 
00082 void Security::readSecretKeys()
00083 {
00084     if (m_gpgRunning) {
00085         QTimer::singleShot(5, this, SLOT(readSecretKeys()));
00086         return;
00087     }
00088     m_runMode = ListSecret;
00089     m_process = new KProcess();
00090     *m_process << "gpg2"
00091     << "--no-secmem-warning"
00092     << "--no-tty"
00093     << "--with-colon"
00094     << "--list-secret-keys";
00095     connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
00096             this, SLOT(slotFinished(int, QProcess::ExitStatus)));
00097     connect(m_process, SIGNAL(readyReadStandardOutput()),
00098             this, SLOT(slotReadyReadStandardOutput()));
00099     m_process->start();
00100     if (!m_process->waitForStarted()) {
00101         delete m_process;
00102         m_process = 0;
00103     } else
00104         m_gpgRunning = true;
00105 }
00106 
00107 void Security::slotFinished(int exitCode, QProcess::ExitStatus exitStatus)
00108 {
00109     if (exitStatus != QProcess::NormalExit) {
00110         m_gpgRunning = false;
00111         delete m_process;
00112         m_process = 0;
00113         return;
00114     }
00115     switch (m_runMode) {
00116     case ListSecret:
00117         m_keysRead = true;
00118         break;
00119     case Verify: emit validityResult(m_result);
00120         break;
00121     case Sign:   emit fileSigned(m_result);
00122         break;
00123 
00124     }
00125     m_gpgRunning = false;
00126     delete m_process;
00127     m_process = 0;
00128 
00129     Q_UNUSED(exitCode)
00130 }
00131 
00132 void Security::slotReadyReadStandardOutput()
00133 {
00134     QString data;
00135     while (m_process->canReadLine()) {
00136         data = QString::fromLocal8Bit(m_process->readLine());
00137         switch (m_runMode) {
00138         case List:
00139         case ListSecret:
00140             if (data.startsWith(QLatin1String("pub")) || data.startsWith(QLatin1String("sec"))) {
00141                 KeyStruct key;
00142                 if (data.startsWith(QLatin1String("pub")))
00143                     key.secret = false;
00144                 else
00145                     key.secret = true;
00146                 QStringList line = data.split(':', QString::KeepEmptyParts);
00147                 key.id = line[4];
00148                 QString shortId = key.id.right(8);
00149                 QString trustStr = line[1];
00150                 key.trusted = false;
00151                 if (trustStr == "u" || trustStr == "f")
00152                     key.trusted = true;
00153                 data = line[9];
00154                 key.mail = data.section('<', -1, -1);
00155                 key.mail.truncate(key.mail.length() - 1);
00156                 key.name = data.section('<', 0, 0);
00157                 if (key.name.contains("("))
00158                     key.name = key.name.section('(', 0, 0);
00159                 m_keys[shortId] = key;
00160             }
00161             break;
00162         case Verify:
00163             data = data.section(']', 1, -1).trimmed();
00164             if (data.startsWith(QLatin1String("GOODSIG"))) {
00165                 m_result &= SIGNED_BAD_CLEAR;
00166                 m_result |= SIGNED_OK;
00167                 QString id = data.section(' ', 1 , 1).right(8);
00168                 if (!m_keys.contains(id)) {
00169                     m_result |= UNKNOWN;
00170                 } else {
00171                     m_signatureKey = m_keys[id];
00172                 }
00173             } else
00174                 if (data.startsWith(QLatin1String("NO_PUBKEY"))) {
00175                     m_result &= SIGNED_BAD_CLEAR;
00176                     m_result |= UNKNOWN;
00177                 } else
00178                     if (data.startsWith(QLatin1String("BADSIG"))) {
00179                         m_result |= SIGNED_BAD;
00180                         QString id = data.section(' ', 1 , 1).right(8);
00181                         if (!m_keys.contains(id)) {
00182                             m_result |= UNKNOWN;
00183                         } else {
00184                             m_signatureKey = m_keys[id];
00185                         }
00186                     } else
00187                         if (data.startsWith(QLatin1String("TRUST_ULTIMATE"))) {
00188                             m_result &= SIGNED_BAD_CLEAR;
00189                             m_result |= TRUSTED;
00190                         }
00191             break;
00192 
00193         case Sign:
00194             if (data.contains("passphrase.enter")) {
00195                 KeyStruct key = m_keys[m_secretKey];
00196                 QPointer<KPasswordDialog> dlg = new KPasswordDialog(NULL);
00197                 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));
00198                 if (dlg->exec()) {
00199                     m_process->write(dlg->password().toLocal8Bit() + '\n');
00200             delete dlg;
00201                 } else {
00202                     m_result |= BAD_PASSPHRASE;
00203                     m_process->kill();
00204             delete dlg;
00205                     return;
00206                 }
00207             } else
00208                 if (data.contains("BAD_PASSPHRASE")) {
00209                     m_result |= BAD_PASSPHRASE;
00210                 }
00211             break;
00212         }
00213     }
00214 }
00215 
00216 void Security::checkValidity(const QString& filename)
00217 {
00218     m_fileName = filename;
00219     slotCheckValidity();
00220 }
00221 
00222 void Security::slotCheckValidity()
00223 {
00224     if (!m_keysRead || m_gpgRunning) {
00225         QTimer::singleShot(5, this, SLOT(slotCheckValidity()));
00226         return;
00227     }
00228     if (m_keys.count() == 0) {
00229         emit validityResult(-1);
00230         return;
00231     }
00232 
00233     m_result = 0;
00234     m_runMode = Verify;
00235     QFileInfo f(m_fileName);
00236     //check the MD5 sum
00237     QString md5sum;
00238     const char* c = "";
00239     KMD5 context(c);
00240     QFile file(m_fileName);
00241     if (file.open(QIODevice::ReadOnly)) {
00242         context.reset();
00243         context.update(file);
00244         md5sum = context.hexDigest();
00245         file.close();
00246     }
00247     file.setFileName(f.path() + "/md5sum");
00248     if (file.open(QIODevice::ReadOnly)) {
00249         QByteArray md5sum_file;
00250         file.readLine(md5sum_file.data(), 50);
00251         if (!md5sum_file.isEmpty() && QString(md5sum_file).startsWith(md5sum))
00252             m_result |= MD5_OK;
00253         file.close();
00254     }
00255     m_result |= SIGNED_BAD;
00256     m_signatureKey.id = "";
00257     m_signatureKey.name = "";
00258     m_signatureKey.mail = "";
00259     m_signatureKey.trusted = false;
00260 
00261     //verify the signature
00262     m_process = new KProcess();
00263     *m_process << "gpg2"
00264     << "--no-secmem-warning"
00265     << "--status-fd=2"
00266     << "--command-fd=0"
00267     << "--verify"
00268     << f.path() + "/signature"
00269     << m_fileName;
00270     connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
00271             this, SLOT(slotFinished(int, QProcess::ExitStatus)));
00272     connect(m_process, SIGNAL(readyReadStandardOutput()),
00273             this, SLOT(slotReadyReadStandardOutput()));
00274     m_process->start();
00275     if (m_process->waitForStarted())
00276         m_gpgRunning = true;
00277     else {
00278         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>"));
00279         emit validityResult(0);
00280         delete m_process;
00281         m_process = 0;
00282     }
00283 }
00284 
00285 void Security::signFile(const QString &fileName)
00286 {
00287     m_fileName = fileName;
00288     slotSignFile();
00289 }
00290 
00291 void Security::slotSignFile()
00292 {
00293     if (!m_keysRead || m_gpgRunning) {
00294         QTimer::singleShot(5, this, SLOT(slotSignFile()));
00295         return;
00296     }
00297 
00298     QStringList secretKeys;
00299     for (QMap<QString, KeyStruct>::Iterator it = m_keys.begin(); it != m_keys.end(); ++it) {
00300         if (it.value().secret)
00301             secretKeys.append(it.key());
00302     }
00303 
00304     if (secretKeys.count() == 0) {
00305         emit fileSigned(-1);
00306         return;
00307     }
00308 
00309     m_result = 0;
00310     QFileInfo f(m_fileName);
00311 
00312     //create the MD5 sum
00313     QString md5sum;
00314     const char* c = "";
00315     KMD5 context(c);
00316     QFile file(m_fileName);
00317     if (file.open(QIODevice::ReadOnly)) {
00318         context.reset();
00319         context.update(file);
00320         md5sum = context.hexDigest();
00321         file.close();
00322     }
00323     file.setFileName(f.path() + "/md5sum");
00324     if (file.open(QIODevice::WriteOnly)) {
00325         QTextStream stream(&file);
00326         stream << md5sum;
00327         m_result |= MD5_OK;
00328         file.close();
00329     }
00330 
00331     if (secretKeys.count() > 1) {
00332         bool ok;
00333         secretKeys = KInputDialog::getItemList(i18n("Select Signing Key"), i18n("Key used for signing:"), secretKeys, QStringList(secretKeys[0]), false, &ok);
00334         if (ok)
00335             m_secretKey = secretKeys[0];
00336         else {
00337             emit fileSigned(0);
00338             return;
00339         }
00340     } else
00341         m_secretKey = secretKeys[0];
00342 
00343     //verify the signature
00344     m_process = new KProcess();
00345     *m_process << "gpg2"
00346     << "--no-secmem-warning"
00347     << "--status-fd=2"
00348     << "--command-fd=0"
00349     << "--no-tty"
00350     << "--detach-sign"
00351     << "-u"
00352     << m_secretKey
00353     << "-o"
00354     << f.path() + "/signature"
00355     << m_fileName;
00356     connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
00357             this, SLOT(slotFinished(int, QProcess::ExitStatus)));
00358     connect(m_process, SIGNAL(readyReadStandardOutput()),
00359             this, SLOT(slotReadyReadStandardOutput()));
00360     m_runMode = Sign;
00361     m_process->start();
00362     if (m_process->waitForStarted())
00363         m_gpgRunning = true;
00364     else {
00365         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>"));
00366         emit fileSigned(0);
00367         delete m_process;
00368         m_process = 0;
00369     }
00370 }
00371 
00372 #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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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