File indexing completed on 2024-06-02 05:24:20
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 conf/smimevalidationconfigurationwidget.cpp 0003 0004 This file is part of Kleopatra, the KDE keymanager 0005 SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include <config-kleopatra.h> 0011 0012 #include "smimevalidationconfigurationwidget.h" 0013 0014 #include "ui_smimevalidationconfigurationwidget.h" 0015 0016 #include "labelledwidget.h" 0017 0018 #include "smimevalidationpreferences.h" 0019 0020 #include <Libkleo/Compat> 0021 0022 #include <QGpgME/CryptoConfig> 0023 0024 #include "kleopatra_debug.h" 0025 #include <KLocalizedString> 0026 0027 #if HAVE_QDBUS 0028 #include <QDBusConnection> 0029 #endif 0030 0031 using namespace Kleo; 0032 using namespace Kleo::Config; 0033 using namespace QGpgME; 0034 0035 class SMimeValidationConfigurationWidget::Private 0036 { 0037 friend class ::Kleo::Config::SMimeValidationConfigurationWidget; 0038 SMimeValidationConfigurationWidget *const q; 0039 0040 public: 0041 explicit Private(SMimeValidationConfigurationWidget *qq) 0042 : q(qq) 0043 , ui(qq) 0044 { 0045 #if HAVE_QDBUS 0046 QDBusConnection::sessionBus().connect(QString(), QString(), QStringLiteral("org.kde.kleo.CryptoConfig"), QStringLiteral("changed"), q, SLOT(load())); 0047 #endif 0048 auto changedSignal = &SMimeValidationConfigurationWidget::changed; 0049 connect(ui.intervalRefreshCB, &QCheckBox::toggled, q, changedSignal); 0050 connect(ui.intervalRefreshSB, &QSpinBox::valueChanged, q, changedSignal); 0051 connect(ui.OCSPCB, &QCheckBox::toggled, q, changedSignal); 0052 connect(ui.OCSPResponderURL, &QLineEdit::textChanged, q, changedSignal); 0053 0054 auto certRequesterSignal = &KleopatraClientCopy::Gui::CertificateRequester::selectedCertificatesChanged; 0055 connect(ui.OCSPResponderSignature, certRequesterSignal, q, changedSignal); 0056 0057 connect(ui.doNotCheckCertPolicyCB, &QCheckBox::toggled, q, changedSignal); 0058 connect(ui.neverConsultCB, &QCheckBox::toggled, q, changedSignal); 0059 connect(ui.allowMarkTrustedCB, &QCheckBox::toggled, q, changedSignal); 0060 connect(ui.fetchMissingCB, &QCheckBox::toggled, q, changedSignal); 0061 connect(ui.ignoreServiceURLCB, &QCheckBox::toggled, q, changedSignal); 0062 connect(ui.ignoreHTTPDPCB, &QCheckBox::toggled, q, changedSignal); 0063 connect(ui.disableHTTPCB, &QCheckBox::toggled, q, changedSignal); 0064 connect(ui.honorHTTPProxyRB, &QRadioButton::toggled, q, changedSignal); 0065 connect(ui.useCustomHTTPProxyRB, &QRadioButton::toggled, q, changedSignal); 0066 connect(ui.customHTTPProxy, &QLineEdit::textChanged, q, changedSignal); 0067 connect(ui.ignoreLDAPDPCB, &QCheckBox::toggled, q, changedSignal); 0068 connect(ui.disableLDAPCB, &QCheckBox::toggled, q, changedSignal); 0069 connect(ui.customLDAPProxy, &QLineEdit::textChanged, q, changedSignal); 0070 0071 auto enableDisableSlot = [this]() { 0072 enableDisableActions(); 0073 }; 0074 connect(ui.useCustomHTTPProxyRB, &QRadioButton::toggled, q, enableDisableSlot); 0075 connect(ui.disableHTTPCB, &QCheckBox::toggled, q, enableDisableSlot); 0076 } 0077 0078 bool customHTTPProxyWritable = false; 0079 0080 private: 0081 void enableDisableActions() 0082 { 0083 ui.customHTTPProxy->setEnabled(ui.useCustomHTTPProxyRB->isChecked() && !ui.disableHTTPCB->isChecked() && customHTTPProxyWritable); 0084 } 0085 0086 private: 0087 struct UI : Ui_SMimeValidationConfigurationWidget { 0088 LabelledWidget<KleopatraClientCopy::Gui::CertificateRequester> labelledOCSPResponderSignature; 0089 LabelledWidget<QLineEdit> labelledOCSPResponderURL; 0090 0091 explicit UI(SMimeValidationConfigurationWidget *q) 0092 : Ui_SMimeValidationConfigurationWidget() 0093 { 0094 setupUi(q); 0095 0096 labelledOCSPResponderURL.setWidgets(OCSPResponderURL, OCSPResponderURLLabel); 0097 labelledOCSPResponderSignature.setWidgets(OCSPResponderSignature, OCSPResponderSignatureLabel); 0098 0099 OCSPResponderSignature->setOnlyX509CertificatesAllowed(true); 0100 OCSPResponderSignature->setOnlySigningCertificatesAllowed(true); 0101 OCSPResponderSignature->setMultipleCertificatesAllowed(false); 0102 // OCSPResponderSignature->setAllowedKeys( KeySelectionDialog::TrustedKeys|KeySelectionDialog::ValidKeys ); 0103 } 0104 } ui; 0105 }; 0106 0107 SMimeValidationConfigurationWidget::SMimeValidationConfigurationWidget(QWidget *p, Qt::WindowFlags f) 0108 : QWidget(p, f) 0109 , d(new Private(this)) 0110 { 0111 } 0112 0113 SMimeValidationConfigurationWidget::~SMimeValidationConfigurationWidget() 0114 { 0115 } 0116 0117 static void disableDirmngrWidget(QWidget *w) 0118 { 0119 w->setEnabled(false); 0120 w->setWhatsThis(i18n("This option requires dirmngr >= 0.9.0")); 0121 } 0122 0123 static void initializeDirmngrCheckbox(QCheckBox *cb, CryptoConfigEntry *entry) 0124 { 0125 if (entry) { 0126 cb->setChecked(entry->boolValue()); 0127 } 0128 if (!entry || entry->isReadOnly()) { 0129 disableDirmngrWidget(cb); 0130 } 0131 } 0132 0133 struct SMIMECryptoConfigEntries { 0134 enum ShowError { 0135 DoNotShowError, 0136 DoShowError, 0137 }; 0138 0139 SMIMECryptoConfigEntries(CryptoConfig *config) 0140 : mConfig(config) 0141 // Checkboxes 0142 , mCheckUsingOCSPConfigEntry(configEntry("gpgsm", "enable-ocsp", CryptoConfigEntry::ArgType_None)) 0143 , mEnableOCSPsendingConfigEntry(configEntry("dirmngr", "allow-ocsp", CryptoConfigEntry::ArgType_None)) 0144 , mDoNotCheckCertPolicyConfigEntry(configEntry("gpgsm", "disable-policy-checks", CryptoConfigEntry::ArgType_None)) 0145 , mNeverConsultConfigEntry(configEntry("gpgsm", "disable-crl-checks", CryptoConfigEntry::ArgType_None)) 0146 , mAllowMarkTrustedConfigEntry( 0147 configEntry("gpg-agent", "allow-mark-trusted", CryptoConfigEntry::ArgType_None, DoNotShowError)) // legacy entry -> ignore error 0148 , mFetchMissingConfigEntry(configEntry("gpgsm", "auto-issuer-key-retrieve", CryptoConfigEntry::ArgType_None)) 0149 , mNoAllowMarkTrustedConfigEntry(configEntry("gpg-agent", "no-allow-mark-trusted", CryptoConfigEntry::ArgType_None)) 0150 // dirmngr-0.9.0 options 0151 , mIgnoreServiceURLEntry(configEntry("dirmngr", "ignore-ocsp-service-url", CryptoConfigEntry::ArgType_None)) 0152 , mIgnoreHTTPDPEntry(configEntry("dirmngr", "ignore-http-dp", CryptoConfigEntry::ArgType_None)) 0153 , mDisableHTTPEntry(configEntry("dirmngr", "disable-http", CryptoConfigEntry::ArgType_None)) 0154 , mHonorHTTPProxy(configEntry("dirmngr", "honor-http-proxy", CryptoConfigEntry::ArgType_None)) 0155 , mIgnoreLDAPDPEntry(configEntry("dirmngr", "ignore-ldap-dp", CryptoConfigEntry::ArgType_None)) 0156 , mDisableLDAPEntry(configEntry("dirmngr", "disable-ldap", CryptoConfigEntry::ArgType_None)) 0157 // Other widgets 0158 , mOCSPResponderURLConfigEntry(configEntry("dirmngr", "ocsp-responder", CryptoConfigEntry::ArgType_String)) 0159 , mOCSPResponderSignature(configEntry("dirmngr", "ocsp-signer", CryptoConfigEntry::ArgType_String)) 0160 , mCustomHTTPProxy(configEntry("dirmngr", "http-proxy", CryptoConfigEntry::ArgType_String)) 0161 , mCustomLDAPProxy(configEntry("dirmngr", "ldap-proxy", CryptoConfigEntry::ArgType_String)) 0162 { 0163 } 0164 0165 CryptoConfigEntry *configEntry(const char *componentName, const char *entryName, int argType, ShowError showError = DoShowError); 0166 0167 CryptoConfig *const mConfig; 0168 0169 // Checkboxes 0170 CryptoConfigEntry *const mCheckUsingOCSPConfigEntry; 0171 CryptoConfigEntry *const mEnableOCSPsendingConfigEntry; 0172 CryptoConfigEntry *const mDoNotCheckCertPolicyConfigEntry; 0173 CryptoConfigEntry *const mNeverConsultConfigEntry; 0174 CryptoConfigEntry *const mAllowMarkTrustedConfigEntry; 0175 CryptoConfigEntry *const mFetchMissingConfigEntry; 0176 // gnupg 2.0.17+ option that should inhibit allow-mark-trusted display 0177 CryptoConfigEntry *const mNoAllowMarkTrustedConfigEntry; 0178 // dirmngr-0.9.0 options 0179 CryptoConfigEntry *const mIgnoreServiceURLEntry; 0180 CryptoConfigEntry *const mIgnoreHTTPDPEntry; 0181 CryptoConfigEntry *const mDisableHTTPEntry; 0182 CryptoConfigEntry *const mHonorHTTPProxy; 0183 CryptoConfigEntry *const mIgnoreLDAPDPEntry; 0184 CryptoConfigEntry *const mDisableLDAPEntry; 0185 // Other widgets 0186 CryptoConfigEntry *const mOCSPResponderURLConfigEntry; 0187 CryptoConfigEntry *const mOCSPResponderSignature; 0188 CryptoConfigEntry *const mCustomHTTPProxy; 0189 CryptoConfigEntry *const mCustomLDAPProxy; 0190 }; 0191 0192 void SMimeValidationConfigurationWidget::defaults() 0193 { 0194 qCDebug(KLEOPATRA_LOG) << "not implemented"; 0195 } 0196 0197 void SMimeValidationConfigurationWidget::load() 0198 { 0199 const SMimeValidationPreferences preferences; 0200 const unsigned int refreshInterval = preferences.refreshInterval(); 0201 d->ui.intervalRefreshCB->setChecked(refreshInterval > 0); 0202 d->ui.intervalRefreshSB->setValue(refreshInterval); 0203 const bool isRefreshIntervalImmutable = preferences.isImmutable(QStringLiteral("RefreshInterval")); 0204 d->ui.intervalRefreshCB->setEnabled(!isRefreshIntervalImmutable); 0205 d->ui.intervalRefreshSB->setEnabled(!isRefreshIntervalImmutable); 0206 0207 CryptoConfig *const config = QGpgME::cryptoConfig(); 0208 if (!config) { 0209 setEnabled(false); 0210 return; 0211 } 0212 0213 #if 0 0214 // crashes other pages' save() by nuking the CryptoConfigEntries under their feet. 0215 // This was probably not a problem in KMail, where this code comes 0216 // from. But here, it's fatal. 0217 0218 // Force re-parsing gpgconf data, in case e.g. kleopatra or "configure backend" was used 0219 // (which ends up calling us via D-Bus) 0220 config->clear(); 0221 #endif 0222 0223 // Create config entries 0224 // Don't keep them around, they'll get deleted by clear(), which could be 0225 // done by the "configure backend" button even before we save(). 0226 const SMIMECryptoConfigEntries e(config); 0227 0228 // Initialize GUI items from the config entries 0229 0230 if (e.mCheckUsingOCSPConfigEntry) { 0231 d->ui.OCSPCB->setChecked(e.mCheckUsingOCSPConfigEntry->boolValue()); 0232 } 0233 d->ui.OCSPCB->setEnabled(e.mCheckUsingOCSPConfigEntry && !e.mCheckUsingOCSPConfigEntry->isReadOnly()); 0234 d->ui.OCSPGroupBox->setEnabled(d->ui.OCSPCB->isChecked()); 0235 0236 if (e.mDoNotCheckCertPolicyConfigEntry) { 0237 d->ui.doNotCheckCertPolicyCB->setChecked(e.mDoNotCheckCertPolicyConfigEntry->boolValue()); 0238 } 0239 d->ui.doNotCheckCertPolicyCB->setEnabled(e.mDoNotCheckCertPolicyConfigEntry && !e.mDoNotCheckCertPolicyConfigEntry->isReadOnly()); 0240 if (e.mNeverConsultConfigEntry) { 0241 d->ui.neverConsultCB->setChecked(e.mNeverConsultConfigEntry->boolValue()); 0242 } 0243 d->ui.neverConsultCB->setEnabled(e.mNeverConsultConfigEntry && !e.mNeverConsultConfigEntry->isReadOnly()); 0244 if (e.mNoAllowMarkTrustedConfigEntry) { 0245 d->ui.allowMarkTrustedCB->hide(); // this option was only here to _enable_ allow-mark-trusted, and makes no sense if it's already default on 0246 } 0247 if (e.mAllowMarkTrustedConfigEntry) { 0248 d->ui.allowMarkTrustedCB->setChecked(e.mAllowMarkTrustedConfigEntry->boolValue()); 0249 } 0250 d->ui.allowMarkTrustedCB->setEnabled(e.mAllowMarkTrustedConfigEntry && !e.mAllowMarkTrustedConfigEntry->isReadOnly()); 0251 if (e.mFetchMissingConfigEntry) { 0252 d->ui.fetchMissingCB->setChecked(e.mFetchMissingConfigEntry->boolValue()); 0253 } 0254 d->ui.fetchMissingCB->setEnabled(e.mFetchMissingConfigEntry && !e.mFetchMissingConfigEntry->isReadOnly()); 0255 0256 if (e.mOCSPResponderURLConfigEntry) { 0257 d->ui.OCSPResponderURL->setText(e.mOCSPResponderURLConfigEntry->stringValue()); 0258 } 0259 d->ui.labelledOCSPResponderURL.setEnabled(e.mOCSPResponderURLConfigEntry && !e.mOCSPResponderURLConfigEntry->isReadOnly()); 0260 if (e.mOCSPResponderSignature) { 0261 d->ui.OCSPResponderSignature->setSelectedCertificate(e.mOCSPResponderSignature->stringValue()); 0262 } 0263 d->ui.labelledOCSPResponderSignature.setEnabled(e.mOCSPResponderSignature && !e.mOCSPResponderSignature->isReadOnly()); 0264 0265 // dirmngr-0.9.0 options 0266 initializeDirmngrCheckbox(d->ui.ignoreServiceURLCB, e.mIgnoreServiceURLEntry); 0267 initializeDirmngrCheckbox(d->ui.ignoreHTTPDPCB, e.mIgnoreHTTPDPEntry); 0268 initializeDirmngrCheckbox(d->ui.disableHTTPCB, e.mDisableHTTPEntry); 0269 initializeDirmngrCheckbox(d->ui.ignoreLDAPDPCB, e.mIgnoreLDAPDPEntry); 0270 initializeDirmngrCheckbox(d->ui.disableLDAPCB, e.mDisableLDAPEntry); 0271 if (e.mCustomHTTPProxy) { 0272 QString systemProxy = QString::fromLocal8Bit(qgetenv("http_proxy")); 0273 if (systemProxy.isEmpty()) { 0274 systemProxy = i18n("no proxy"); 0275 } 0276 d->ui.systemHTTPProxy->setText(i18n("(Current system setting: %1)", systemProxy)); 0277 const bool honor = e.mHonorHTTPProxy && e.mHonorHTTPProxy->boolValue(); 0278 d->ui.honorHTTPProxyRB->setChecked(honor); 0279 d->ui.useCustomHTTPProxyRB->setChecked(!honor); 0280 d->ui.customHTTPProxy->setText(e.mCustomHTTPProxy->stringValue()); 0281 } 0282 d->customHTTPProxyWritable = e.mCustomHTTPProxy && !e.mCustomHTTPProxy->isReadOnly(); 0283 if (!d->customHTTPProxyWritable) { 0284 disableDirmngrWidget(d->ui.honorHTTPProxyRB); 0285 disableDirmngrWidget(d->ui.useCustomHTTPProxyRB); 0286 disableDirmngrWidget(d->ui.systemHTTPProxy); 0287 disableDirmngrWidget(d->ui.customHTTPProxy); 0288 } 0289 if (e.mCustomLDAPProxy) { 0290 d->ui.customLDAPProxy->setText(e.mCustomLDAPProxy->stringValue()); 0291 } 0292 if (!e.mCustomLDAPProxy || e.mCustomLDAPProxy->isReadOnly()) { 0293 disableDirmngrWidget(d->ui.customLDAPProxy); 0294 disableDirmngrWidget(d->ui.customLDAPLabel); 0295 } 0296 d->enableDisableActions(); 0297 } 0298 0299 static void saveCheckBoxToKleoEntry(QCheckBox *cb, CryptoConfigEntry *entry) 0300 { 0301 const bool b = cb->isChecked(); 0302 if (entry && entry->boolValue() != b) { 0303 entry->setBoolValue(b); 0304 } 0305 } 0306 0307 void SMimeValidationConfigurationWidget::save() const 0308 { 0309 CryptoConfig *const config = QGpgME::cryptoConfig(); 0310 if (!config) { 0311 return; 0312 } 0313 0314 { 0315 SMimeValidationPreferences preferences; 0316 preferences.setRefreshInterval(d->ui.intervalRefreshCB->isChecked() ? d->ui.intervalRefreshSB->value() : 0); 0317 preferences.save(); 0318 } 0319 0320 // Create config entries 0321 // Don't keep them around, they'll get deleted by clear(), which could be done by the 0322 // "configure backend" button. 0323 const SMIMECryptoConfigEntries e(config); 0324 0325 const bool b = d->ui.OCSPCB->isChecked(); 0326 if (e.mCheckUsingOCSPConfigEntry && e.mCheckUsingOCSPConfigEntry->boolValue() != b) { 0327 e.mCheckUsingOCSPConfigEntry->setBoolValue(b); 0328 } 0329 // Set allow-ocsp together with enable-ocsp 0330 if (e.mEnableOCSPsendingConfigEntry && e.mEnableOCSPsendingConfigEntry->boolValue() != b) { 0331 e.mEnableOCSPsendingConfigEntry->setBoolValue(b); 0332 } 0333 0334 saveCheckBoxToKleoEntry(d->ui.doNotCheckCertPolicyCB, e.mDoNotCheckCertPolicyConfigEntry); 0335 saveCheckBoxToKleoEntry(d->ui.neverConsultCB, e.mNeverConsultConfigEntry); 0336 saveCheckBoxToKleoEntry(d->ui.allowMarkTrustedCB, e.mAllowMarkTrustedConfigEntry); 0337 saveCheckBoxToKleoEntry(d->ui.fetchMissingCB, e.mFetchMissingConfigEntry); 0338 0339 QString txt = d->ui.OCSPResponderURL->text(); 0340 if (e.mOCSPResponderURLConfigEntry && e.mOCSPResponderURLConfigEntry->stringValue() != txt) { 0341 e.mOCSPResponderURLConfigEntry->setStringValue(txt); 0342 } 0343 0344 txt = d->ui.OCSPResponderSignature->selectedCertificate(); 0345 if (e.mOCSPResponderSignature && e.mOCSPResponderSignature->stringValue() != txt) { 0346 e.mOCSPResponderSignature->setStringValue(txt); 0347 } 0348 0349 // dirmngr-0.9.0 options 0350 saveCheckBoxToKleoEntry(d->ui.ignoreServiceURLCB, e.mIgnoreServiceURLEntry); 0351 saveCheckBoxToKleoEntry(d->ui.ignoreHTTPDPCB, e.mIgnoreHTTPDPEntry); 0352 saveCheckBoxToKleoEntry(d->ui.disableHTTPCB, e.mDisableHTTPEntry); 0353 saveCheckBoxToKleoEntry(d->ui.ignoreLDAPDPCB, e.mIgnoreLDAPDPEntry); 0354 saveCheckBoxToKleoEntry(d->ui.disableLDAPCB, e.mDisableLDAPEntry); 0355 if (e.mCustomHTTPProxy) { 0356 const bool honor = d->ui.honorHTTPProxyRB->isChecked(); 0357 if (e.mHonorHTTPProxy && e.mHonorHTTPProxy->boolValue() != honor) { 0358 e.mHonorHTTPProxy->setBoolValue(honor); 0359 } 0360 0361 const QString chosenProxy = d->ui.customHTTPProxy->text(); 0362 if (chosenProxy != e.mCustomHTTPProxy->stringValue()) { 0363 e.mCustomHTTPProxy->setStringValue(chosenProxy); 0364 } 0365 } 0366 txt = d->ui.customLDAPProxy->text(); 0367 if (e.mCustomLDAPProxy && e.mCustomLDAPProxy->stringValue() != txt) { 0368 e.mCustomLDAPProxy->setStringValue(d->ui.customLDAPProxy->text()); 0369 } 0370 0371 config->sync(true); 0372 } 0373 0374 CryptoConfigEntry * 0375 SMIMECryptoConfigEntries::configEntry(const char *componentName, const char *entryName, int /*CryptoConfigEntry::ArgType*/ argType, ShowError showError) 0376 { 0377 CryptoConfigEntry *const entry = getCryptoConfigEntry(mConfig, componentName, entryName); 0378 if (!entry) { 0379 if (showError == DoShowError) { 0380 qCWarning(KLEOPATRA_LOG) << QStringLiteral("Backend error: gpgconf doesn't seem to know the entry for %1/%2") 0381 .arg(QLatin1StringView(componentName), QLatin1String(entryName)); 0382 } 0383 return nullptr; 0384 } 0385 if (entry->argType() != argType || entry->isList()) { 0386 if (showError == DoShowError) { 0387 qCWarning(KLEOPATRA_LOG) << QStringLiteral("Backend error: gpgconf has wrong type for %1/%2: %3 %4") 0388 .arg(QLatin1StringView(componentName), QLatin1String(entryName)) 0389 .arg(entry->argType()) 0390 .arg(entry->isList()); 0391 } 0392 return nullptr; 0393 } 0394 return entry; 0395 } 0396 0397 #include "moc_smimevalidationconfigurationwidget.cpp"