File indexing completed on 2024-04-21 16:20:26
0001 /* 0002 SPDX-FileCopyrightText: 2008 Will Stephenson <wstephenson@kde.org> 0003 SPDX-FileCopyrightText: 2013 Lukáš Tinkl <ltinkl@redhat.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "openvpnwidget.h" 0009 #include "openvpnadvancedwidget.h" 0010 #include "plasma_nm_openvpn.h" 0011 0012 #include <QDBusMetaType> 0013 #include <QLineEdit> 0014 #include <QPointer> 0015 #include <QUrl> 0016 0017 #include <KProcess> 0018 #include <KUrlRequester> 0019 0020 #include "nm-openvpn-service.h" 0021 0022 class OpenVpnSettingWidget::Private 0023 { 0024 public: 0025 Ui_OpenVPNProp ui; 0026 NetworkManager::VpnSetting::Ptr setting; 0027 class EnumConnectionType 0028 { 0029 public: 0030 enum ConnectionType { Certificates = 0, Psk, Password, CertsPassword }; 0031 }; 0032 class EnumKeyDirection 0033 { 0034 public: 0035 enum KeyDirection { None = 0, D0, D1 }; 0036 }; 0037 }; 0038 0039 OpenVpnSettingWidget::OpenVpnSettingWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent) 0040 : SettingWidget(setting, parent) 0041 , d(new Private) 0042 { 0043 qDBusRegisterMetaType<NMStringMap>(); 0044 0045 d->ui.setupUi(this); 0046 d->setting = setting; 0047 0048 d->ui.x509KeyPassword->setPasswordOptionsEnabled(true); 0049 d->ui.x509KeyPassword->setPasswordNotRequiredEnabled(true); 0050 d->ui.passPassword->setPasswordOptionsEnabled(true); 0051 d->ui.passPassword->setPasswordNotRequiredEnabled(true); 0052 d->ui.x509PassKeyPassword->setPasswordOptionsEnabled(true); 0053 d->ui.x509PassKeyPassword->setPasswordNotRequiredEnabled(true); 0054 d->ui.x509PassPassword->setPasswordOptionsEnabled(true); 0055 d->ui.x509PassPassword->setPasswordNotRequiredEnabled(true); 0056 0057 // use requesters' urlSelected signals to set other requester's startDirs to save clicking 0058 // around the filesystem 0059 QList<const KUrlRequester *> requesters{ 0060 d->ui.x509CaFile, 0061 d->ui.x509Cert, 0062 d->ui.x509Key, 0063 d->ui.pskSharedKey, 0064 d->ui.passCaFile, 0065 d->ui.x509PassCaFile, 0066 d->ui.x509PassCert, 0067 d->ui.x509PassKey, 0068 }; 0069 for (const KUrlRequester *requester : requesters) { 0070 connect(requester, &KUrlRequester::urlSelected, this, &OpenVpnSettingWidget::updateStartDir); 0071 } 0072 0073 connect(d->ui.btnAdvanced, &QPushButton::clicked, this, &OpenVpnSettingWidget::showAdvanced); 0074 0075 // Connect for setting check 0076 watchChangedSetting(); 0077 0078 // Connect for validity check 0079 connect(d->ui.gateway, &QLineEdit::textChanged, this, &OpenVpnSettingWidget::slotWidgetChanged); 0080 0081 KAcceleratorManager::manage(this); 0082 0083 if (setting && !setting->isNull()) { 0084 loadConfig(d->setting); 0085 } 0086 } 0087 0088 OpenVpnSettingWidget::~OpenVpnSettingWidget() 0089 { 0090 delete d; 0091 } 0092 0093 void OpenVpnSettingWidget::loadConfig(const NetworkManager::Setting::Ptr &setting) 0094 { 0095 Q_UNUSED(setting) 0096 0097 // General settings 0098 const NMStringMap dataMap = d->setting->data(); 0099 const QString cType = dataMap.value(NM_OPENVPN_KEY_CONNECTION_TYPE); 0100 0101 if (cType == QLatin1String(NM_OPENVPN_CONTYPE_PASSWORD_TLS)) { 0102 d->ui.cmbConnectionType->setCurrentIndex(Private::EnumConnectionType::CertsPassword); 0103 d->ui.x509PassUsername->setText(dataMap[NM_OPENVPN_KEY_USERNAME]); 0104 d->ui.x509PassCaFile->setUrl(QUrl::fromLocalFile(dataMap[NM_OPENVPN_KEY_CA])); 0105 d->ui.x509PassCert->setUrl(QUrl::fromLocalFile(dataMap[NM_OPENVPN_KEY_CERT])); 0106 d->ui.x509PassKey->setUrl(QUrl::fromLocalFile(dataMap[NM_OPENVPN_KEY_KEY])); 0107 } else if (cType == QLatin1String(NM_OPENVPN_CONTYPE_STATIC_KEY)) { 0108 d->ui.cmbConnectionType->setCurrentIndex(Private::EnumConnectionType::Psk); 0109 d->ui.pskSharedKey->setText(dataMap[NM_OPENVPN_KEY_STATIC_KEY]); 0110 if (dataMap.contains(NM_OPENVPN_KEY_STATIC_KEY_DIRECTION)) { 0111 switch (dataMap[NM_OPENVPN_KEY_STATIC_KEY_DIRECTION].toUInt()) { 0112 case 0: 0113 d->ui.cmbKeyDirection->setCurrentIndex(Private::EnumKeyDirection::D0); 0114 break; 0115 case 1: 0116 d->ui.cmbKeyDirection->setCurrentIndex(Private::EnumKeyDirection::D1); 0117 break; 0118 } 0119 } else { 0120 d->ui.cmbKeyDirection->setCurrentIndex(Private::EnumKeyDirection::None); 0121 } 0122 d->ui.pskRemoteIp->setText(dataMap[NM_OPENVPN_KEY_REMOTE_IP]); 0123 d->ui.pskLocalIp->setText(dataMap[NM_OPENVPN_KEY_LOCAL_IP]); 0124 } else if (cType == QLatin1String(NM_OPENVPN_CONTYPE_PASSWORD)) { 0125 d->ui.cmbConnectionType->setCurrentIndex(Private::EnumConnectionType::Password); 0126 d->ui.passUserName->setText(dataMap[NM_OPENVPN_KEY_USERNAME]); 0127 d->ui.passCaFile->setUrl(QUrl::fromLocalFile(dataMap[NM_OPENVPN_KEY_CA])); 0128 } else if (cType == QLatin1String(NM_OPENVPN_CONTYPE_TLS)) { 0129 d->ui.cmbConnectionType->setCurrentIndex(Private::EnumConnectionType::Certificates); 0130 d->ui.x509CaFile->setUrl(QUrl::fromLocalFile(dataMap[NM_OPENVPN_KEY_CA])); 0131 d->ui.x509Cert->setUrl(QUrl::fromLocalFile(dataMap[NM_OPENVPN_KEY_CERT])); 0132 d->ui.x509Key->setUrl(QUrl::fromLocalFile(dataMap[NM_OPENVPN_KEY_KEY])); 0133 } 0134 0135 d->ui.gateway->setText(dataMap[NM_OPENVPN_KEY_REMOTE]); 0136 0137 NetworkManager::Setting::SecretFlags type; 0138 0139 if (cType == QLatin1String(NM_OPENVPN_CONTYPE_TLS)) { 0140 type = (NetworkManager::Setting::SecretFlags)dataMap[NM_OPENVPN_KEY_CERTPASS "-flags"].toInt(); 0141 fillOnePasswordCombo(d->ui.x509KeyPassword, type); 0142 } else if (cType == QLatin1String(NM_OPENVPN_CONTYPE_PASSWORD)) { 0143 type = (NetworkManager::Setting::SecretFlags)dataMap[NM_OPENVPN_KEY_PASSWORD "-flags"].toInt(); 0144 fillOnePasswordCombo(d->ui.passPassword, type); 0145 } else if (cType == QLatin1String(NM_OPENVPN_CONTYPE_PASSWORD_TLS)) { 0146 type = (NetworkManager::Setting::SecretFlags)dataMap[NM_OPENVPN_KEY_PASSWORD "-flags"].toInt(); 0147 fillOnePasswordCombo(d->ui.x509PassPassword, type); 0148 type = (NetworkManager::Setting::SecretFlags)dataMap[NM_OPENVPN_KEY_CERTPASS "-flags"].toInt(); 0149 fillOnePasswordCombo(d->ui.x509PassKeyPassword, type); 0150 } 0151 0152 loadSecrets(setting); 0153 } 0154 0155 void OpenVpnSettingWidget::loadSecrets(const NetworkManager::Setting::Ptr &setting) 0156 { 0157 NetworkManager::VpnSetting::Ptr vpnSetting = setting.staticCast<NetworkManager::VpnSetting>(); 0158 0159 if (vpnSetting) { 0160 const QString cType = d->setting->data().value(NM_OPENVPN_KEY_CONNECTION_TYPE); 0161 const NMStringMap secrets = vpnSetting->secrets(); 0162 0163 if (cType == QLatin1String(NM_OPENVPN_CONTYPE_TLS)) { 0164 d->ui.x509KeyPassword->setText(secrets.value(NM_OPENVPN_KEY_CERTPASS)); 0165 } else if (cType == QLatin1String(NM_OPENVPN_CONTYPE_PASSWORD)) { 0166 d->ui.passPassword->setText(secrets.value(NM_OPENVPN_KEY_PASSWORD)); 0167 } else if (cType == QLatin1String(NM_OPENVPN_CONTYPE_PASSWORD_TLS)) { 0168 d->ui.x509PassPassword->setText(secrets.value(NM_OPENVPN_KEY_PASSWORD)); 0169 d->ui.x509PassKeyPassword->setText(secrets.value(NM_OPENVPN_KEY_CERTPASS)); 0170 } 0171 } 0172 } 0173 0174 QVariantMap OpenVpnSettingWidget::setting() const 0175 { 0176 NMStringMap data = d->setting->data(); 0177 NMStringMap secretData = d->setting->secrets(); 0178 NetworkManager::VpnSetting setting; 0179 setting.setServiceType(QLatin1String(NM_DBUS_SERVICE_OPENVPN)); 0180 // required settings 0181 data.insert(QLatin1String(NM_OPENVPN_KEY_REMOTE), d->ui.gateway->text()); 0182 0183 QString contype; 0184 0185 switch (d->ui.cmbConnectionType->currentIndex()) { 0186 case Private::EnumConnectionType::Certificates: 0187 contype = QLatin1String(NM_OPENVPN_CONTYPE_TLS); 0188 // qCDebug(PLASMA_NM_OPENVPN_LOG) << "saving VPN TLS settings as urls:" << d->ui.x509CaFile->url() << d->ui.x509Cert->url() << d->ui.x509Key->url(); 0189 data.insert(QLatin1String(NM_OPENVPN_KEY_CA), d->ui.x509CaFile->url().toLocalFile()); 0190 data.insert(QLatin1String(NM_OPENVPN_KEY_CERT), d->ui.x509Cert->url().toLocalFile()); 0191 data.insert(QLatin1String(NM_OPENVPN_KEY_KEY), d->ui.x509Key->url().toLocalFile()); 0192 // key password 0193 if (!d->ui.x509KeyPassword->text().isEmpty()) { 0194 secretData.insert(QLatin1String(NM_OPENVPN_KEY_CERTPASS), d->ui.x509KeyPassword->text()); 0195 } else { 0196 secretData.remove(QLatin1String(NM_OPENVPN_KEY_CERTPASS)); 0197 } 0198 handleOnePasswordType(d->ui.x509KeyPassword, QLatin1String(NM_OPENVPN_KEY_CERTPASS "-flags"), data); 0199 break; 0200 case Private::EnumConnectionType::Psk: 0201 contype = QLatin1String(NM_OPENVPN_CONTYPE_STATIC_KEY); 0202 data.insert(QLatin1String(NM_OPENVPN_KEY_STATIC_KEY), d->ui.pskSharedKey->url().toLocalFile()); 0203 switch (d->ui.cmbKeyDirection->currentIndex()) { 0204 case Private::EnumKeyDirection::None: 0205 break; 0206 case Private::EnumKeyDirection::D0: 0207 data.insert(QLatin1String(NM_OPENVPN_KEY_STATIC_KEY_DIRECTION), QString::number(0)); 0208 break; 0209 case Private::EnumKeyDirection::D1: 0210 data.insert(QLatin1String(NM_OPENVPN_KEY_STATIC_KEY_DIRECTION), QString::number(1)); 0211 break; 0212 } 0213 // ip addresses 0214 data.insert(QLatin1String(NM_OPENVPN_KEY_REMOTE_IP), d->ui.pskRemoteIp->text()); 0215 data.insert(QLatin1String(NM_OPENVPN_KEY_LOCAL_IP), d->ui.pskLocalIp->text()); 0216 break; 0217 case Private::EnumConnectionType::Password: 0218 contype = QLatin1String(NM_OPENVPN_CONTYPE_PASSWORD); 0219 // username 0220 if (!d->ui.passUserName->text().isEmpty()) { 0221 data.insert(QLatin1String(NM_OPENVPN_KEY_USERNAME), d->ui.passUserName->text()); 0222 } else { 0223 data.remove(QLatin1String(NM_OPENVPN_KEY_USERNAME)); 0224 } 0225 // password 0226 if (!d->ui.passPassword->text().isEmpty()) { 0227 secretData.insert(QLatin1String(NM_OPENVPN_KEY_PASSWORD), d->ui.passPassword->text()); 0228 } else { 0229 secretData.remove(QLatin1String(NM_OPENVPN_KEY_PASSWORD)); 0230 } 0231 handleOnePasswordType(d->ui.passPassword, QLatin1String(NM_OPENVPN_KEY_PASSWORD "-flags"), data); 0232 // ca 0233 data.insert(QLatin1String(NM_OPENVPN_KEY_CA), d->ui.passCaFile->url().toLocalFile()); 0234 break; 0235 case Private::EnumConnectionType::CertsPassword: 0236 contype = QLatin1String(NM_OPENVPN_CONTYPE_PASSWORD_TLS); 0237 // username 0238 if (!d->ui.x509PassUsername->text().isEmpty()) { 0239 data.insert(QLatin1String(NM_OPENVPN_KEY_USERNAME), d->ui.x509PassUsername->text()); 0240 } else { 0241 data.remove(QLatin1String(NM_OPENVPN_KEY_USERNAME)); 0242 } 0243 // ca 0244 data.insert(QLatin1String(NM_OPENVPN_KEY_CA), d->ui.x509PassCaFile->url().toLocalFile()); 0245 // cert 0246 data.insert(QLatin1String(NM_OPENVPN_KEY_CERT), d->ui.x509PassCert->url().toLocalFile()); 0247 // key file 0248 data.insert(QLatin1String(NM_OPENVPN_KEY_KEY), d->ui.x509PassKey->url().toLocalFile()); 0249 // key password 0250 if (!d->ui.x509PassKeyPassword->text().isEmpty()) { 0251 secretData.insert(QLatin1String(NM_OPENVPN_KEY_CERTPASS), d->ui.x509PassKeyPassword->text()); 0252 } else { 0253 secretData.remove(QLatin1String(NM_OPENVPN_KEY_CERTPASS)); 0254 } 0255 handleOnePasswordType(d->ui.x509PassKeyPassword, QLatin1String(NM_OPENVPN_KEY_CERTPASS "-flags"), data); 0256 // password 0257 if (!d->ui.x509PassPassword->text().isEmpty()) { 0258 secretData.insert(QLatin1String(NM_OPENVPN_KEY_PASSWORD), d->ui.x509PassPassword->text()); 0259 } else { 0260 secretData.remove(QLatin1String(NM_OPENVPN_KEY_PASSWORD)); 0261 } 0262 handleOnePasswordType(d->ui.x509PassPassword, QLatin1String(NM_OPENVPN_KEY_PASSWORD "-flags"), data); 0263 break; 0264 } 0265 data.insert(QLatin1String(NM_OPENVPN_KEY_CONNECTION_TYPE), contype); 0266 0267 setting.setData(data); 0268 setting.setSecrets(secretData); 0269 0270 return setting.toMap(); 0271 } 0272 0273 void OpenVpnSettingWidget::updateStartDir(const QUrl &url) 0274 { 0275 QList<KUrlRequester *> requesters; 0276 requesters << d->ui.x509CaFile << d->ui.x509Cert << d->ui.x509Key << d->ui.pskSharedKey << d->ui.passCaFile << d->ui.x509PassCaFile << d->ui.x509PassCert 0277 << d->ui.x509PassKey; 0278 for (KUrlRequester *requester : std::as_const(requesters)) { 0279 requester->setStartDir(url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash)); 0280 } 0281 } 0282 0283 void OpenVpnSettingWidget::setPasswordType(QLineEdit *edit, int type) 0284 { 0285 edit->setEnabled(type == SettingWidget::EnumPasswordStorageType::Store); 0286 } 0287 0288 void OpenVpnSettingWidget::fillOnePasswordCombo(PasswordField *passwordField, NetworkManager::Setting::SecretFlags type) 0289 { 0290 if (type.testFlag(NetworkManager::Setting::None)) { 0291 passwordField->setPasswordOption(PasswordField::StoreForAllUsers); 0292 } else if (type.testFlag(NetworkManager::Setting::AgentOwned)) { 0293 passwordField->setPasswordOption(PasswordField::StoreForUser); 0294 } else if (type.testFlag(NetworkManager::Setting::NotSaved)) { 0295 passwordField->setPasswordOption(PasswordField::AlwaysAsk); 0296 } else if (type.testFlag(NetworkManager::Setting::NotRequired)) { 0297 passwordField->setPasswordOption(PasswordField::NotRequired); 0298 } 0299 } 0300 0301 void OpenVpnSettingWidget::handleOnePasswordType(const PasswordField *passwordField, const QString &key, NMStringMap &data) const 0302 { 0303 const PasswordField::PasswordOption option = passwordField->passwordOption(); 0304 switch (option) { 0305 case PasswordField::StoreForAllUsers: 0306 data.insert(key, QString::number(NetworkManager::Setting::None)); 0307 break; 0308 case PasswordField::StoreForUser: 0309 data.insert(key, QString::number(NetworkManager::Setting::AgentOwned)); 0310 break; 0311 case PasswordField::AlwaysAsk: 0312 data.insert(key, QString::number(NetworkManager::Setting::NotSaved)); 0313 break; 0314 case PasswordField::NotRequired: 0315 data.insert(key, QString::number(NetworkManager::Setting::NotRequired)); 0316 break; 0317 } 0318 } 0319 0320 void OpenVpnSettingWidget::showAdvanced() 0321 { 0322 QPointer<OpenVpnAdvancedWidget> adv = new OpenVpnAdvancedWidget(d->setting, this); 0323 adv->setAttribute(Qt::WA_DeleteOnClose); 0324 adv->init(); 0325 connect(adv.data(), &OpenVpnAdvancedWidget::accepted, [adv, this]() { 0326 NetworkManager::VpnSetting::Ptr advData = adv->setting(); 0327 if (!advData.isNull()) { 0328 d->setting->setData(advData->data()); 0329 d->setting->setSecrets(advData->secrets()); 0330 } 0331 }); 0332 adv->setModal(true); 0333 adv->show(); 0334 } 0335 0336 bool OpenVpnSettingWidget::isValid() const 0337 { 0338 return !d->ui.gateway->text().isEmpty(); 0339 }