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