diff --git a/src/utils/gnupg-helper.cpp b/src/utils/gnupg-helper.cpp deleted file mode 100644 index 481e0a5be..000000000 --- a/src/utils/gnupg-helper.cpp +++ /dev/null @@ -1,406 +0,0 @@ -/* -*- mode: c++; c-basic-offset:4 -*- - utils/gnupg-helper.cpp - - This file is part of Kleopatra, the KDE keymanager - SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB - - SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik - SPDX-FileContributor: Intevation GmbH - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include - -#include "gnupg-helper.h" - -#include "utils/hex.h" - -#include -#include -#include - -#include -#include - -#include "kleopatra_debug.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_OS_WIN -#include "gnupg-registry.h" -#endif // Q_OS_WIN - -#include -#include - -using namespace GpgME; - -QString Kleo::gnupgHomeDirectory() -{ -#ifdef Q_OS_WIN - return QFile::decodeName(default_homedir()); -#else - const QByteArray gnupgHome = qgetenv("GNUPGHOME"); - if (!gnupgHome.isEmpty()) { - return QFile::decodeName(gnupgHome); - } else { - return QDir::homePath() + QLatin1String("/.gnupg"); - } -#endif -} - -int Kleo::makeGnuPGError(int code) -{ - return gpg_error(static_cast(code)); -} - -static QString findGpgExe(GpgME::Engine engine, const QString &exe) -{ - const GpgME::EngineInfo info = GpgME::engineInfo(engine); - return info.fileName() ? QFile::decodeName(info.fileName()) : QStandardPaths::findExecutable(exe); -} - -QString Kleo::gpgConfPath() -{ - static const auto path = findGpgExe(GpgME::GpgConfEngine, QStringLiteral("gpgconf")); - return path; -} - -QString Kleo::gpgSmPath() -{ - static const auto path = findGpgExe(GpgME::GpgSMEngine, QStringLiteral("gpgsm")); - return path; -} - -QString Kleo::gpgPath() -{ - static const auto path = findGpgExe(GpgME::GpgEngine, QStringLiteral("gpg")); - return path; -} - -QStringList Kleo::gnupgFileWhitelist() -{ - return QStringList() - // The obvious pubring - << QStringLiteral("pubring.gpg") - // GnuPG 2.1 pubring - << QStringLiteral("pubring.kbx") - // Trust in X509 Certificates - << QStringLiteral("trustlist.txt") - // Trustdb controls ownertrust and thus WOT validity - << QStringLiteral("trustdb.gpg") - // We want to update when smartcard status changes - << QStringLiteral("reader*.status") - // No longer used in 2.1 but for 2.0 we want this - << QStringLiteral("secring.gpg") - // Changes to the trustmodel / compliance mode might - // affect validity so we check this, too. - // Globbing for gpg.conf* here will trigger too often - // as gpgconf creates files like gpg.conf.bak or - // gpg.conf.tmp12312.gpgconf that should not trigger - // a change. - << QStringLiteral("gpg.conf") - << QStringLiteral("gpg.conf-?") - << QStringLiteral("gpg.conf-?.?") - ; -} - -QString Kleo::gpg4winVersion() -{ - QFile versionFile(gpg4winInstallPath() + QStringLiteral("/../VERSION")); - if (!versionFile.open(QIODevice::ReadOnly)) { - // No need to translate this should only be the case in development - // builds. - return QStringLiteral("Unknown (no VERSION file found)"); - } - const QString g4wTag = QString::fromUtf8(versionFile.readLine()); - if (!g4wTag.startsWith(QLatin1String("gpg4win"))) { - // Hu? Something unknown - return QStringLiteral("Unknown (invalid VERSION file found)"); - } - // Next line is version. - return QString::fromUtf8(versionFile.readLine()).trimmed(); -} - -QString Kleo::gpg4winInstallPath() -{ -#ifdef Q_OS_WIN - // QApplication::applicationDirPath is only used as a fallback - // to support the case where Kleopatra is not installed from - // Gpg4win but Gpg4win is also installed. - char *instDir = read_w32_registry_string("HKEY_LOCAL_MACHINE", - "Software\\GPG4Win", - "Install Directory"); - if (!instDir) { - // Fallback to HKCU - instDir = read_w32_registry_string("HKEY_CURRENT_USER", - "Software\\GPG4Win", - "Install Directory"); - } - if (instDir) { - QString ret = QString::fromLocal8Bit(instDir) + QStringLiteral("/bin"); - free(instDir); - return ret; - } - qCDebug(KLEOPATRA_LOG) << "Gpg4win not found. Falling back to Kleopatra instdir."; -#endif - return QCoreApplication::applicationDirPath(); -} - -QString Kleo::gnupgInstallPath() -{ - -#ifdef Q_OS_WIN - // QApplication::applicationDirPath is only used as a fallback - // to support the case where Kleopatra is not installed from - // Gpg4win but Gpg4win is also installed. - char *instDir = read_w32_registry_string("HKEY_LOCAL_MACHINE", - "Software\\GnuPG", - "Install Directory"); - if (!instDir) { - // Fallback to HKCU - instDir = read_w32_registry_string("HKEY_CURRENT_USER", - "Software\\GnuPG", - "Install Directory"); - } - if (instDir) { - QString ret = QString::fromLocal8Bit(instDir) + QStringLiteral("/bin"); - free(instDir); - return ret; - } - qCDebug(KLEOPATRA_LOG) << "GnuPG not found. Falling back to gpgconf list dir."; -#endif - return gpgConfListDir("bindir"); -} - -QString Kleo::gpgConfListDir(const char *which) -{ - if (!which || !*which) { - return QString(); - } - const QString gpgConfPath = Kleo::gpgConfPath(); - if (gpgConfPath.isEmpty()) { - return QString(); - } - QProcess gpgConf; - qCDebug(KLEOPATRA_LOG) << "gpgConfListDir: starting " << qPrintable(gpgConfPath) << " --list-dirs"; - gpgConf.start(gpgConfPath, QStringList() << QStringLiteral("--list-dirs")); - if (!gpgConf.waitForFinished()) { - qCDebug(KLEOPATRA_LOG) << "gpgConfListDir(): failed to execute gpgconf: " << qPrintable(gpgConf.errorString()); - qCDebug(KLEOPATRA_LOG) << "output was:\n" << gpgConf.readAllStandardError().constData(); - return QString(); - } - const QList lines = gpgConf.readAllStandardOutput().split('\n'); - for (const QByteArray &line : lines) - if (line.startsWith(which) && line[qstrlen(which)] == ':') { - const int begin = qstrlen(which) + 1; - int end = line.size(); - while (end && (line[end - 1] == '\n' || line[end - 1] == '\r')) { - --end; - } - const QString result = QDir::fromNativeSeparators(QFile::decodeName(hexdecode(line.mid(begin, end - begin)))); - qCDebug(KLEOPATRA_LOG) << "gpgConfListDir: found " << qPrintable(result) - << " for '" << which << "'entry"; - return result; - } - qCDebug(KLEOPATRA_LOG) << "gpgConfListDir(): didn't find '" << which << "'" - << "entry in output:\n" << gpgConf.readAllStandardError().constData(); - return QString(); -} - -static std::array getVersionFromString(const char *actual, bool &ok) -{ - std::array ret; - ok = false; - - if (!actual) { - return ret; - } - - QString versionString = QString::fromLatin1(actual); - - // Try to fix it up - QRegExp rx(QLatin1String("(\\d+)\\.(\\d+)\\.(\\d+)(?:-svn\\d+)?.*")); - for (int i = 0; i < 3; i++) { - if (!rx.exactMatch(versionString)) { - versionString += QStringLiteral(".0"); - } else { - ok = true; - break; - } - } - - if (!ok) { - qCDebug(KLEOPATRA_LOG) << "Can't parse version " << actual; - return ret; - } - - for (int i = 0; i < 3; ++i) { - ret[i] = rx.cap(i + 1).toUInt(&ok); - if (!ok) { - return ret; - } - } - - ok = true; - return ret; -} - -bool Kleo::versionIsAtLeast(const char *minimum, const char *actual) -{ - if (!minimum || !actual) { - return false; - } - bool ok; - const auto minimum_version = getVersionFromString(minimum, ok); - if (!ok) { - return false; - } - const auto actual_version = getVersionFromString(actual, ok); - if (!ok) { - return false; - } - - return !std::lexicographical_compare(std::begin(actual_version), std::end(actual_version), - std::begin(minimum_version), std::end(minimum_version)); - -} - -bool Kleo::engineIsVersion(int major, int minor, int patch, GpgME::Engine engine) -{ - static QMap > cachedVersions; - const int required_version[] = {major, minor, patch}; - // Gpgconf means spawning processes which is expensive on windows. - std::array actual_version; - if (!cachedVersions.contains(engine)) { - const Error err = checkEngine(engine); - if (err.code() == GPG_ERR_INV_ENGINE) { - qCDebug(KLEOPATRA_LOG) << "isVersion: invalid engine. '"; - return false; - } - - const char *actual = GpgME::engineInfo(engine).version(); - bool ok; - actual_version = getVersionFromString(actual, ok); - - qCDebug(KLEOPATRA_LOG) << "Parsed" << actual << "as: " - << actual_version[0] << '.' - << actual_version[1] << '.' - << actual_version[2] << '.'; - if (!ok) { - return false; - } - cachedVersions.insert(engine, actual_version); - } else { - actual_version = cachedVersions.value(engine); - } - - // return ! ( actual_version < required_version ) - return !std::lexicographical_compare(std::begin(actual_version), std::end(actual_version), - std::begin(required_version), std::end(required_version)); -} - -const QString& Kleo::paperKeyInstallPath() -{ - static const QString pkPath = QStandardPaths::findExecutable(QStringLiteral("paperkey"), QStringList() << QCoreApplication::applicationDirPath()).isEmpty() ? - QStandardPaths::findExecutable(QStringLiteral("paperkey")) : - QStandardPaths::findExecutable(QStringLiteral("paperkey"), QStringList() << QCoreApplication::applicationDirPath()); - return pkPath; -} - -bool Kleo::haveKeyserverConfigured() -{ - if (engineIsVersion(2, 1, 19)) { - // since 2.1.19 there is a builtin keyserver - return true; - } - const QGpgME::CryptoConfig *const config = QGpgME::cryptoConfig(); - if (!config) { - return false; - } - const QGpgME::CryptoConfigEntry *const entry = config->entry(QStringLiteral("gpg"), QStringLiteral("Keyserver"), QStringLiteral("keyserver")); - return entry && !entry->stringValue().isEmpty(); -} - -bool Kleo::gpgComplianceP(const char *mode) -{ - const auto conf = QGpgME::cryptoConfig(); - const auto entry = conf->entry(QStringLiteral("gpg"), - QStringLiteral("Configuration"), - QStringLiteral("compliance")); - - return entry && entry->stringValue() == QString::fromLatin1(mode); -} - -enum GpgME::UserID::Validity Kleo::keyValidity(const GpgME::Key &key) -{ - enum UserID::Validity validity = UserID::Validity::Unknown; - - for (const auto &uid: key.userIDs()) { - if (validity == UserID::Validity::Unknown - || validity > uid.validity()) { - validity = uid.validity(); - } - } - - return validity; -} - -#ifdef Q_OS_WIN -static QString fromEncoding (unsigned int src_encoding, const char *data) -{ - int n = MultiByteToWideChar(src_encoding, 0, data, -1, NULL, 0); - if (n < 0) { - return QString(); - } - - wchar_t *result = (wchar_t *) malloc ((n+1) * sizeof *result); - - n = MultiByteToWideChar(src_encoding, 0, data, -1, result, n); - if (n < 0) { - free(result); - return QString(); - } - const auto ret = QString::fromWCharArray(result, n); - free(result); - return ret; -} -#endif - -QString Kleo::stringFromGpgOutput(const QByteArray &ba) -{ -#ifdef Q_OS_WIN - /* Qt on Windows uses GetACP while GnuPG prefers - * GetConsoleOutputCP. - * - * As we are not a console application GetConsoleOutputCP - * usually returns 0. - * From experience the closest thing that let's us guess - * what GetConsoleOutputCP returns for a console application - * it appears to be the OEMCP. - */ - unsigned int cpno = GetConsoleOutputCP (); - if (!cpno) { - cpno = GetOEMCP(); - } - if (!cpno) { - cpno = GetACP(); - } - if (!cpno) { - qCDebug(KLEOPATRA_LOG) << "Failed to find native codepage"; - return QString(); - } - - return fromEncoding(cpno, ba.constData()); -#else - return QString::fromLocal8Bit(ba); -#endif -} diff --git a/src/utils/gnupg-helper.h b/src/utils/gnupg-helper.h deleted file mode 100644 index 9ce4e39a4..000000000 --- a/src/utils/gnupg-helper.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- mode: c++; c-basic-offset:4 -*- - utils/gnupg-helper.h - - This file is part of Kleopatra, the KDE keymanager - SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef __KLEOPATRA_GNUPGHELPER_H__ -#define __KLEOPATRA_GNUPGHELPER_H__ - -#include -#include - -/* Does the given object comply with DE_VS? This macro can be used to - ensure that we can still build against older versions of GPGME - without cluttering the code with preprocessor conditionals. */ -# define IS_DE_VS(x) (x).isDeVs() - -class QString; -class QStringList; -class QByteArray; - -namespace Kleo -{ - -QString gnupgHomeDirectory(); - -QString gpgConfPath(); -QString gpgSmPath(); -QString gpgPath(); - -QString gpgConfListDir(const char *which); -QString gpg4winInstallPath(); -QString gpg4winVersion(); -QString gnupgInstallPath(); -const QString& paperKeyInstallPath(); - -QStringList gnupgFileWhitelist(); -int makeGnuPGError(int code); - -bool engineIsVersion(int major, int minor, int patch, GpgME::Engine = GpgME::GpgConfEngine); -bool haveKeyserverConfigured(); -bool gpgComplianceP(const char *mode); -enum GpgME::UserID::Validity keyValidity(const GpgME::Key &key); - -/* Convert GnuPG output to a QString with proper encoding. - * Takes Gpg Quirks into account and might handle future - * changes in GnuPG Output. */ -QString stringFromGpgOutput(const QByteArray &ba); - -/* Check if a minimum version is there. Strings should be in the format: - * 1.2.3 */ - -bool versionIsAtLeast(const char *minimum, const char *actual); -} - -#endif // __KLEOPATRA_GNUPGHELPER_H__