• Skip to content
  • Skip to link menu
KDE 4.3 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/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 KNS;
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 << "gpg"
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 << "gpg"
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("pub") || data.startsWith("sec")) {
00141                 KeyStruct key;
00142                 if (data.startsWith("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("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("NO_PUBKEY")) {
00175                     m_result &= SIGNED_BAD_CLEAR;
00176                     m_result |= UNKNOWN;
00177                 } else
00178                     if (data.startsWith("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("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                 } else {
00201                     m_result |= BAD_PASSPHRASE;
00202                     m_process->kill();
00203                     return;
00204                 }
00205             } else
00206                 if (data.contains("BAD_PASSPHRASE")) {
00207                     m_result |= BAD_PASSPHRASE;
00208                 }
00209             break;
00210         }
00211     }
00212 }
00213 
00214 void Security::checkValidity(const QString& filename)
00215 {
00216     m_fileName = filename;
00217     slotCheckValidity();
00218 }
00219 
00220 void Security::slotCheckValidity()
00221 {
00222     if (!m_keysRead || m_gpgRunning) {
00223         QTimer::singleShot(5, this, SLOT(slotCheckValidity()));
00224         return;
00225     }
00226     if (m_keys.count() == 0) {
00227         emit validityResult(-1);
00228         return;
00229     }
00230 
00231     m_result = 0;
00232     m_runMode = Verify;
00233     QFileInfo f(m_fileName);
00234     //check the MD5 sum
00235     QString md5sum;
00236     const char* c = "";
00237     KMD5 context(c);
00238     QFile file(m_fileName);
00239     if (file.open(QIODevice::ReadOnly)) {
00240         context.reset();
00241         context.update(file);
00242         md5sum = context.hexDigest();
00243         file.close();
00244     }
00245     file.setFileName(f.path() + "/md5sum");
00246     if (file.open(QIODevice::ReadOnly)) {
00247         QByteArray md5sum_file;
00248         file.readLine(md5sum_file.data(), 50);
00249         if (!md5sum_file.isEmpty() && QString(md5sum_file).startsWith(md5sum))
00250             m_result |= MD5_OK;
00251         file.close();
00252     }
00253     m_result |= SIGNED_BAD;
00254     m_signatureKey.id = "";
00255     m_signatureKey.name = "";
00256     m_signatureKey.mail = "";
00257     m_signatureKey.trusted = false;
00258 
00259     //verify the signature
00260     m_process = new KProcess();
00261     *m_process << "gpg"
00262     << "--no-secmem-warning"
00263     << "--status-fd=2"
00264     << "--command-fd=0"
00265     << "--verify"
00266     << f.path() + "/signature"
00267     << m_fileName;
00268     connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
00269             this, SLOT(slotFinished(int, QProcess::ExitStatus)));
00270     connect(m_process, SIGNAL(readyReadStandardOutput()),
00271             this, SLOT(slotReadyReadStandardOutput()));
00272     m_process->start();
00273     if (m_process->waitForStarted())
00274         m_gpgRunning = true;
00275     else {
00276         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>"));
00277         emit validityResult(0);
00278         delete m_process;
00279         m_process = 0;
00280     }
00281 }
00282 
00283 void Security::signFile(const QString &fileName)
00284 {
00285     m_fileName = fileName;
00286     slotSignFile();
00287 }
00288 
00289 void Security::slotSignFile()
00290 {
00291     if (!m_keysRead || m_gpgRunning) {
00292         QTimer::singleShot(5, this, SLOT(slotSignFile()));
00293         return;
00294     }
00295 
00296     QStringList secretKeys;
00297     for (QMap<QString, KeyStruct>::Iterator it = m_keys.begin(); it != m_keys.end(); ++it) {
00298         if (it.value().secret)
00299             secretKeys.append(it.key());
00300     }
00301 
00302     if (secretKeys.count() == 0) {
00303         emit fileSigned(-1);
00304         return;
00305     }
00306 
00307     m_result = 0;
00308     QFileInfo f(m_fileName);
00309 
00310     //create the MD5 sum
00311     QString md5sum;
00312     const char* c = "";
00313     KMD5 context(c);
00314     QFile file(m_fileName);
00315     if (file.open(QIODevice::ReadOnly)) {
00316         context.reset();
00317         context.update(file);
00318         md5sum = context.hexDigest();
00319         file.close();
00320     }
00321     file.setFileName(f.path() + "/md5sum");
00322     if (file.open(QIODevice::WriteOnly)) {
00323         QTextStream stream(&file);
00324         stream << md5sum;
00325         m_result |= MD5_OK;
00326         file.close();
00327     }
00328 
00329     if (secretKeys.count() > 1) {
00330         bool ok;
00331         secretKeys = KInputDialog::getItemList(i18n("Select Signing Key"), i18n("Key used for signing:"), secretKeys, QStringList(secretKeys[0]), false, &ok);
00332         if (ok)
00333             m_secretKey = secretKeys[0];
00334         else {
00335             emit fileSigned(0);
00336             return;
00337         }
00338     } else
00339         m_secretKey = secretKeys[0];
00340 
00341     //verify the signature
00342     m_process = new KProcess();
00343     *m_process << "gpg"
00344     << "--no-secmem-warning"
00345     << "--status-fd=2"
00346     << "--command-fd=0"
00347     << "--no-tty"
00348     << "--detach-sign"
00349     << "-u"
00350     << m_secretKey
00351     << "-o"
00352     << f.path() + "/signature"
00353     << m_fileName;
00354     connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
00355             this, SLOT(slotFinished(int, QProcess::ExitStatus)));
00356     connect(m_process, SIGNAL(readyReadStandardOutput()),
00357             this, SLOT(slotReadyReadStandardOutput()));
00358     m_runMode = Sign;
00359     m_process->start();
00360     if (m_process->waitForStarted())
00361         m_gpgRunning = true;
00362     else {
00363         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>"));
00364         emit fileSigned(0);
00365         delete m_process;
00366         m_process = 0;
00367     }
00368 }
00369 
00370 #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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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