diff options
Diffstat (limited to 'lib/compatibility/knewstuff/security.cpp')
-rw-r--r-- | lib/compatibility/knewstuff/security.cpp | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/lib/compatibility/knewstuff/security.cpp b/lib/compatibility/knewstuff/security.cpp new file mode 100644 index 00000000..f7099c72 --- /dev/null +++ b/lib/compatibility/knewstuff/security.cpp @@ -0,0 +1,344 @@ +/*************************************************************************** + security.cpp - description + ------------------- + begin : Thu Jun 24 11:22:12 2004 + copyright : (C) 2004, 2005 by Andras Mantia <[email protected]> + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Library General Public License as * + * published by the Free Software Foundation; version 2 of the License. * + * * + ***************************************************************************/ + + //qt includes +#include <qfile.h> +#include <qfileinfo.h> +#include <qstringlist.h> +#include <qtimer.h> + + //kde includes +#include <kdebug.h> +#include <kinputdialog.h> +#include <klocale.h> +#include <kmdcodec.h> +#include <kmessagebox.h> +#include <kpassdlg.h> +#include <kprocio.h> + + //app includes +#include "security.h" + +using namespace KNS; + +Security::Security() +{ + m_keysRead = false; + m_gpgRunning = false; + readKeys(); + readSecretKeys(); +} + + +Security::~Security() +{ +} + +void Security::readKeys() +{ + if (m_gpgRunning) + { + QTimer::singleShot(5, this, SLOT(readKeys())); + return; + } + m_runMode = List; + m_keys.clear(); + KProcIO *readProcess=new KProcIO(); + *readProcess << "gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--with-colon"<<"--list-keys"; + connect(readProcess, SIGNAL(processExited(KProcess *)), this, SLOT(slotProcessExited(KProcess *))); + connect(readProcess, SIGNAL(readReady(KProcIO *)) ,this, SLOT(slotDataArrived(KProcIO *))); + if (!readProcess->start(KProcess::NotifyOnExit, true)) + 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>")); + else + m_gpgRunning = true; +} + +void Security::readSecretKeys() +{ + if (m_gpgRunning) + { + QTimer::singleShot(5, this, SLOT(readSecretKeys())); + return; + } + m_runMode = ListSecret; + KProcIO *readProcess=new KProcIO(); + *readProcess << "gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--with-colon"<<"--list-secret-keys"; + connect(readProcess, SIGNAL(processExited(KProcess *)), this, SLOT(slotProcessExited(KProcess *))); + connect(readProcess, SIGNAL(readReady(KProcIO *)) ,this, SLOT(slotDataArrived(KProcIO *))); + if (readProcess->start(KProcess::NotifyOnExit, true)) + m_gpgRunning = true; +} + +void Security::slotProcessExited(KProcess *process) +{ + switch (m_runMode) + { + case ListSecret: + m_keysRead = true; + break; + case Verify: emit validityResult(m_result); + break; + case Sign: emit fileSigned(m_result); + break; + + } + m_gpgRunning = false; + delete process; +} + +void Security::slotDataArrived(KProcIO *procIO) +{ + QString data; + while (procIO->readln(data, true) != -1) + { + switch (m_runMode) + { + case List: + case ListSecret: + if (data.startsWith("pub") || data.startsWith("sec")) + { + KeyStruct key; + if (data.startsWith("pub")) + key.secret = false; + else + key.secret = true; + QStringList line = QStringList::split(":", data, true); + key.id = line[4]; + QString shortId = key.id.right(8); + QString trustStr = line[1]; + key.trusted = false; + if (trustStr == "u" || trustStr == "f") + key.trusted = true; + data = line[9]; + key.mail=data.section('<', -1, -1); + key.mail.truncate(key.mail.length() - 1); + key.name=data.section('<',0,0); + if (key.name.find("(")!=-1) + key.name=key.name.section('(',0,0); + m_keys[shortId] = key; + } + break; + case Verify: + data = data.section("]",1,-1).stripWhiteSpace(); + if (data.startsWith("GOODSIG")) + { + m_result &= SIGNED_BAD_CLEAR; + m_result |= SIGNED_OK; + QString id = data.section(" ", 1 , 1).right(8); + if (!m_keys.contains(id)) + { + m_result |= UNKNOWN; + } else + { + m_signatureKey = m_keys[id]; + } + } else + if (data.startsWith("NO_PUBKEY")) + { + m_result &= SIGNED_BAD_CLEAR; + m_result |= UNKNOWN; + } else + if (data.startsWith("BADSIG")) + { + m_result |= SIGNED_BAD; + QString id = data.section(" ", 1 , 1).right(8); + if (!m_keys.contains(id)) + { + m_result |= UNKNOWN; + } else + { + m_signatureKey = m_keys[id]; + } + } else + if (data.startsWith("TRUST_ULTIMATE")) + { + m_result &= SIGNED_BAD_CLEAR; + m_result |= TRUSTED; + } + break; + + case Sign: + if (data.find("passphrase.enter") != -1) + { + QCString password; + KeyStruct key = m_keys[m_secretKey]; + int result = KPasswordDialog::getPassword(password, i18n("<qt>Enter passphrase for key <b>0x%1</b>, belonging to<br><i>%2<%3></i>:</qt>").arg(m_secretKey).arg(key.name).arg(key.mail)); + if (result == KPasswordDialog::Accepted) + { + procIO->writeStdin(password, true); + password.fill(' '); + } + else + { + m_result |= BAD_PASSPHRASE; + slotProcessExited(procIO); + return; + } + } else + if (data.find("BAD_PASSPHRASE") != -1) + { + m_result |= BAD_PASSPHRASE; + } + break; + } + } +} + +void Security::checkValidity(const QString& filename) +{ + m_fileName = filename; + slotCheckValidity(); +} + +void Security::slotCheckValidity() +{ + if (!m_keysRead || m_gpgRunning) + { + QTimer::singleShot(5, this, SLOT(slotCheckValidity())); + return; + } + if (m_keys.count() == 0) + { + emit validityResult(-1); + return; + } + + m_result = 0; + m_runMode = Verify; + QFileInfo f(m_fileName); + //check the MD5 sum + QString md5sum; + const char* c = ""; + KMD5 context(c); + QFile file(m_fileName); + if (file.open(IO_ReadOnly)) + { + context.reset(); + context.update(file); + md5sum = context.hexDigest(); + file.close(); + } + file.setName(f.dirPath() + "/md5sum"); + if (file.open(IO_ReadOnly)) + { + QString md5sum_file; + file.readLine(md5sum_file, 50); + if (!md5sum.isEmpty() && !md5sum_file.isEmpty() && md5sum_file.startsWith(md5sum)) + m_result |= MD5_OK; + file.close(); + } + m_result |= SIGNED_BAD; + m_signatureKey.id = ""; + m_signatureKey.name = ""; + m_signatureKey.mail = ""; + m_signatureKey.trusted = false; + + //verify the signature + KProcIO *verifyProcess=new KProcIO(); + *verifyProcess<<"gpg"<<"--no-secmem-warning"<<"--status-fd=2"<<"--command-fd=0"<<"--verify" << f.dirPath() + "/signature"<< m_fileName; + connect(verifyProcess, SIGNAL(processExited(KProcess *)),this, SLOT(slotProcessExited(KProcess *))); + connect(verifyProcess, SIGNAL(readReady(KProcIO *)),this, SLOT(slotDataArrived(KProcIO *))); + if (verifyProcess->start(KProcess::NotifyOnExit,true)) + m_gpgRunning = true; + else + { + 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>")); + emit validityResult(0); + delete verifyProcess; + } +} + +void Security::signFile(const QString &fileName) +{ + m_fileName = fileName; + slotSignFile(); +} + +void Security::slotSignFile() +{ + if (!m_keysRead || m_gpgRunning) + { + QTimer::singleShot(5, this, SLOT(slotSignFile())); + return; + } + + QStringList secretKeys; + for (QMap<QString, KeyStruct>::Iterator it = m_keys.begin(); it != m_keys.end(); ++it) + { + if (it.data().secret) + secretKeys.append(it.key()); + } + + if (secretKeys.count() == 0) + { + emit fileSigned(-1); + return; + } + + m_result = 0; + QFileInfo f(m_fileName); + + //create the MD5 sum + QString md5sum; + const char* c = ""; + KMD5 context(c); + QFile file(m_fileName); + if (file.open(IO_ReadOnly)) + { + context.reset(); + context.update(file); + md5sum = context.hexDigest(); + file.close(); + } + file.setName(f.dirPath() + "/md5sum"); + if (file.open(IO_WriteOnly)) + { + QTextStream stream(&file); + stream << md5sum; + m_result |= MD5_OK; + file.close(); + } + + if (secretKeys.count() > 1) + { + bool ok; + secretKeys = KInputDialog::getItemList(i18n("Select Signing Key"), i18n("Key used for signing:"), secretKeys, secretKeys[0], false, &ok); + if (ok) + m_secretKey = secretKeys[0]; + else + { + emit fileSigned(0); + return; + } + } else + m_secretKey = secretKeys[0]; + + //verify the signature + KProcIO *signProcess=new KProcIO(); + *signProcess<<"gpg"<<"--no-secmem-warning"<<"--status-fd=2"<<"--command-fd=0"<<"--no-tty"<<"--detach-sign" << "-u" << m_secretKey << "-o" << f.dirPath() + "/signature" << m_fileName; + connect(signProcess, SIGNAL(processExited(KProcess *)),this, SLOT(slotProcessExited(KProcess *))); + connect(signProcess, SIGNAL(readReady(KProcIO *)),this, SLOT(slotDataArrived(KProcIO *))); + m_runMode = Sign; + if (signProcess->start(KProcess::NotifyOnExit,true)) + m_gpgRunning = true; + else + { + 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>")); + emit fileSigned(0); + delete signProcess; + } +} + +#include "security.moc" |