File indexing completed on 2024-04-21 16:20:26

0001 /*
0002     SPDX-FileCopyrightText: 2013 Lukas Tinkl <ltinkl@redhat.com>
0003     SPDX-FileCopyrightText: 2015 Jan Grulich <jgrulich@redhat.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #include "openvpnadvancedwidget.h"
0009 #include "nm-openvpn-service.h"
0010 #include "settingwidget.h"
0011 #include "ui_openvpnadvanced.h"
0012 
0013 #include <QComboBox>
0014 #include <QStandardPaths>
0015 #include <QUrl>
0016 
0017 #include <KAcceleratorManager>
0018 #include <KLocalizedString>
0019 #include <KProcess>
0020 
0021 class OpenVpnAdvancedWidget::Private
0022 {
0023 public:
0024     NetworkManager::VpnSetting::Ptr setting;
0025     KProcess *openvpnCipherProcess = nullptr;
0026     KProcess *openvpnVersionProcess = nullptr;
0027     QByteArray openvpnCiphers;
0028     QByteArray openVpnVersion;
0029     bool gotOpenVpnCiphers = false;
0030     bool gotOpenVpnVersion = false;
0031     bool readConfig = false;
0032     int versionX = 0;
0033     int versionY = 0;
0034     int versionZ = 0;
0035 
0036     class EnumProxyType
0037     {
0038     public:
0039         enum ProxyType { NotRequired = 0, HTTP = 1, SOCKS = 2 };
0040     };
0041     class EnumHashingAlgorithms
0042     {
0043     public:
0044         enum HashingAlgorithms { Default = 0, None, Md4, Md5, Sha1, Sha224, Sha256, Sha384, Sha512, Ripemd160 };
0045     };
0046     class EnumCompression
0047     {
0048     public:
0049         enum Compression { None = 0, LZO, LZ4, LZ4v2, Adaptive, Automatic };
0050     };
0051 };
0052 
0053 OpenVpnAdvancedWidget::OpenVpnAdvancedWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent)
0054     : QDialog(parent)
0055     , m_ui(new Ui::OpenVpnAdvancedWidget)
0056     , d(new Private)
0057 {
0058     m_ui->setupUi(this);
0059 
0060     setWindowTitle(i18nc("@title: window advanced openvpn properties", "Advanced OpenVPN properties"));
0061 
0062     d->setting = setting;
0063 
0064     m_ui->proxyPassword->setPasswordOptionsEnabled(true);
0065     m_ui->proxyPassword->setPasswordNotRequiredEnabled(true);
0066 
0067     connect(m_ui->cbCertCheck, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &OpenVpnAdvancedWidget::certCheckTypeChanged);
0068     connect(m_ui->cmbProxyType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &OpenVpnAdvancedWidget::proxyTypeChanged);
0069     connect(m_ui->cboTLSMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
0070         if (index == 0) {
0071             m_ui->kurlTlsAuthKey->setDisabled(true);
0072             m_ui->cboDirection->setDisabled(true);
0073         } else if (index == 1) { // TLS-Auth
0074             m_ui->kurlTlsAuthKey->setEnabled(true);
0075             m_ui->cboDirection->setEnabled(true);
0076         } else { // TLS-Crypt
0077             m_ui->kurlTlsAuthKey->setEnabled(true);
0078             m_ui->cboDirection->setDisabled(true);
0079         }
0080     });
0081 
0082     // start openVPN process and get its cipher list
0083     const QString openVpnBinary = QStandardPaths::findExecutable("openvpn", QStringList{"/sbin", "/usr/sbin"});
0084     const QStringList ciphersArgs(QLatin1String("--show-ciphers"));
0085     const QStringList versionArgs(QLatin1String("--version"));
0086 
0087     d->openvpnCipherProcess = new KProcess(this);
0088     d->openvpnCipherProcess->setOutputChannelMode(KProcess::OnlyStdoutChannel);
0089     d->openvpnCipherProcess->setReadChannel(QProcess::StandardOutput);
0090     connect(d->openvpnCipherProcess, &KProcess::errorOccurred, this, &OpenVpnAdvancedWidget::openVpnCipherError);
0091     connect(d->openvpnCipherProcess, &KProcess::readyReadStandardOutput, this, &OpenVpnAdvancedWidget::gotOpenVpnCipherOutput);
0092     connect(d->openvpnCipherProcess, QOverload<int, QProcess::ExitStatus>::of(&KProcess::finished), this, &OpenVpnAdvancedWidget::openVpnCipherFinished);
0093     d->openvpnCipherProcess->setProgram(openVpnBinary, ciphersArgs);
0094 
0095     d->openvpnVersionProcess = new KProcess(this);
0096     d->openvpnVersionProcess->setOutputChannelMode(KProcess::OnlyStdoutChannel);
0097     d->openvpnVersionProcess->setReadChannel(QProcess::StandardOutput);
0098     connect(d->openvpnVersionProcess, &KProcess::errorOccurred, this, &OpenVpnAdvancedWidget::openVpnVersionError);
0099     connect(d->openvpnVersionProcess, &KProcess::readyReadStandardOutput, this, &OpenVpnAdvancedWidget::gotOpenVpnVersionOutput);
0100     connect(d->openvpnVersionProcess, QOverload<int, QProcess::ExitStatus>::of(&KProcess::finished), this, &OpenVpnAdvancedWidget::openVpnVersionFinished);
0101     d->openvpnVersionProcess->setProgram(openVpnBinary, versionArgs);
0102 
0103     connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &OpenVpnAdvancedWidget::accept);
0104     connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &OpenVpnAdvancedWidget::reject);
0105 
0106     KAcceleratorManager::manage(this);
0107 
0108     if (d->setting) {
0109         loadConfig();
0110     }
0111 }
0112 
0113 OpenVpnAdvancedWidget::~OpenVpnAdvancedWidget()
0114 {
0115     delete d;
0116 }
0117 
0118 void OpenVpnAdvancedWidget::init()
0119 {
0120     d->openvpnCipherProcess->start();
0121     d->openvpnVersionProcess->start();
0122 }
0123 
0124 void OpenVpnAdvancedWidget::gotOpenVpnCipherOutput()
0125 {
0126     d->openvpnCiphers.append(d->openvpnCipherProcess->readAll());
0127 }
0128 
0129 void OpenVpnAdvancedWidget::openVpnCipherError(QProcess::ProcessError)
0130 {
0131     m_ui->cboCipher->removeItem(0);
0132     m_ui->cboCipher->addItem(i18nc("@item:inlistbox Item added when OpenVPN cipher lookup failed", "OpenVPN cipher lookup failed"));
0133 }
0134 
0135 void OpenVpnAdvancedWidget::openVpnCipherFinished(int exitCode, QProcess::ExitStatus exitStatus)
0136 {
0137     m_ui->cboCipher->removeItem(0);
0138     if (!exitCode && exitStatus == QProcess::NormalExit) {
0139         m_ui->cboCipher->addItem(i18nc("@item::inlist Default openvpn cipher item", "Default"));
0140         const QList<QByteArray> rawOutputLines = d->openvpnCiphers.split('\n');
0141         bool foundFirstSpace = false;
0142         for (const QByteArray &cipher : rawOutputLines) {
0143             if (cipher.length() == 0) {
0144                 foundFirstSpace = true;
0145             } else if (foundFirstSpace) {
0146                 m_ui->cboCipher->addItem(QString::fromLocal8Bit(cipher.left(cipher.indexOf(' '))));
0147             }
0148         }
0149 
0150         if (m_ui->cboCipher->count()) {
0151             m_ui->cboCipher->setEnabled(true);
0152         } else {
0153             m_ui->cboCipher->addItem(i18nc("@item:inlistbox Item added when OpenVPN cipher lookup failed", "No OpenVPN ciphers found"));
0154         }
0155     } else {
0156         m_ui->cboCipher->addItem(i18nc("@item:inlistbox Item added when OpenVPN cipher lookup failed", "OpenVPN cipher lookup failed"));
0157     }
0158     delete d->openvpnCipherProcess;
0159     d->openvpnCipherProcess = nullptr;
0160     d->openvpnCiphers = QByteArray();
0161     d->gotOpenVpnCiphers = true;
0162 
0163     if (d->readConfig) {
0164         const NMStringMap dataMap = d->setting->data();
0165         if (dataMap.contains(NM_OPENVPN_KEY_CIPHER)) {
0166             m_ui->cboCipher->setCurrentIndex(m_ui->cboCipher->findText(dataMap.value(NM_OPENVPN_KEY_CIPHER)));
0167         }
0168     }
0169 }
0170 
0171 void OpenVpnAdvancedWidget::gotOpenVpnVersionOutput()
0172 {
0173     d->openVpnVersion.append(d->openvpnVersionProcess->readAll());
0174 }
0175 
0176 void OpenVpnAdvancedWidget::openVpnVersionError(QProcess::ProcessError)
0177 {
0178     // We couldn't identify OpenVPN version so disable tls-remote
0179     disableLegacySubjectMatch();
0180 }
0181 
0182 void OpenVpnAdvancedWidget::openVpnVersionFinished(int exitCode, QProcess::ExitStatus exitStatus)
0183 {
0184     // OpenVPN returns 1 when you use "--help" and unfortunately returns 1 even when some error occurs
0185     if (exitCode == 1 && exitStatus == QProcess::NormalExit) {
0186         QStringList list = QString(d->openVpnVersion).split(QLatin1Char(' '));
0187         if (list.count() > 2) {
0188             const QStringList versionList = list.at(1).split(QLatin1Char('.'));
0189             if (versionList.count() == 3) {
0190                 d->versionX = versionList.at(0).toInt();
0191                 d->versionY = versionList.at(1).toInt();
0192                 d->versionZ = versionList.at(2).toInt();
0193 
0194                 if (compareVersion(2, 4, 0) >= 0) {
0195                     disableLegacySubjectMatch();
0196                 }
0197             }
0198         }
0199     } else {
0200         disableLegacySubjectMatch();
0201     }
0202 
0203     delete d->openvpnVersionProcess;
0204     d->openvpnVersionProcess = nullptr;
0205     d->openVpnVersion = QByteArray();
0206     d->gotOpenVpnVersion = true;
0207 
0208     if (d->readConfig) {
0209         const NMStringMap dataMap = d->setting->data();
0210         if (dataMap.contains(NM_OPENVPN_KEY_TLS_REMOTE)) {
0211             m_ui->subjectMatch->setText(dataMap.value(NM_OPENVPN_KEY_TLS_REMOTE));
0212         }
0213     }
0214 }
0215 
0216 int OpenVpnAdvancedWidget::compareVersion(const int x, const int y, const int z) const
0217 {
0218     if (d->versionX == 0) {
0219         // Not valid version
0220         return -2;
0221     }
0222 
0223     if (d->versionX > x) {
0224         return 1;
0225     } else if (d->versionX < x) {
0226         return -1;
0227     } else if (d->versionY > y) {
0228         return 1;
0229     } else if (d->versionY < y) {
0230         return -1;
0231     } else if (d->versionZ > z) {
0232         return 1;
0233     } else if (d->versionZ < z) {
0234         return -1;
0235     }
0236     return 0;
0237 }
0238 
0239 void OpenVpnAdvancedWidget::disableLegacySubjectMatch()
0240 {
0241     m_ui->cbCertCheck->removeItem(CertCheckType::VerifySubjectPartially);
0242 }
0243 
0244 void OpenVpnAdvancedWidget::loadConfig()
0245 {
0246     const NMStringMap dataMap = d->setting->data();
0247     const NMStringMap secrets = d->setting->secrets();
0248 
0249     // Optional Settings
0250     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_PORT))) {
0251         m_ui->chkCustomPort->setChecked(true);
0252         m_ui->sbCustomPort->setValue(dataMap[QLatin1String(NM_OPENVPN_KEY_PORT)].toUInt());
0253     } else {
0254         m_ui->chkCustomPort->setChecked(false);
0255         m_ui->sbCustomPort->setValue(1194); // Default value
0256     }
0257     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_TUNNEL_MTU))) {
0258         m_ui->chkMtu->setChecked(true);
0259         m_ui->sbMtu->setValue(dataMap[QLatin1String(NM_OPENVPN_KEY_TUNNEL_MTU)].toUInt());
0260     } else {
0261         m_ui->chkMtu->setChecked(false);
0262         m_ui->sbMtu->setValue(1500); // Default value
0263     }
0264     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_FRAGMENT_SIZE))) {
0265         m_ui->chkCustomFragmentSize->setChecked(true);
0266         m_ui->sbCustomFragmentSize->setValue(dataMap[QLatin1String(NM_OPENVPN_KEY_FRAGMENT_SIZE)].toUInt());
0267     } else {
0268         m_ui->chkCustomFragmentSize->setChecked(false);
0269         m_ui->sbCustomFragmentSize->setValue(1300);
0270     }
0271 
0272     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_RENEG_SECONDS))) {
0273         m_ui->chkUseCustomReneg->setChecked(true);
0274         m_ui->sbCustomReneg->setValue(dataMap[QLatin1String(NM_OPENVPN_KEY_RENEG_SECONDS)].toUInt());
0275     } else {
0276         m_ui->chkUseCustomReneg->setChecked(false);
0277         m_ui->sbCustomReneg->setValue(0);
0278     }
0279 
0280     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_COMP_LZO))) {
0281         const QString compLzo = dataMap[QLatin1String(NM_OPENVPN_KEY_COMP_LZO)];
0282         if (compLzo == QLatin1String("no-by-default")) {
0283             m_ui->cmbUseCompression->setCurrentIndex(Private::EnumCompression::None);
0284         } else if (compLzo == QLatin1String("yes")) {
0285             m_ui->cmbUseCompression->setCurrentIndex(Private::EnumCompression::LZO);
0286         } else {
0287             m_ui->cmbUseCompression->setCurrentIndex(Private::EnumCompression::Adaptive);
0288         }
0289         m_ui->chkUseCompression->setChecked(true);
0290     }
0291     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_COMPRESS))) {
0292         const QString compress = dataMap[QLatin1String(NM_OPENVPN_KEY_COMPRESS)];
0293         if (compress == QLatin1String("lz4")) {
0294             m_ui->cmbUseCompression->setCurrentIndex(Private::EnumCompression::LZ4);
0295         } else if (compress == QLatin1String("lz4-v2")) {
0296             m_ui->cmbUseCompression->setCurrentIndex(Private::EnumCompression::LZ4v2);
0297         } else if (compress == QLatin1String("lzo")) {
0298             m_ui->cmbUseCompression->setCurrentIndex(Private::EnumCompression::LZO);
0299         } else if (compress == QLatin1String("yes")) {
0300             m_ui->cmbUseCompression->setCurrentIndex(Private::EnumCompression::Automatic);
0301         } else {
0302             m_ui->cmbUseCompression->setCurrentIndex(Private::EnumCompression::Automatic);
0303         }
0304         m_ui->chkUseCompression->setChecked(true);
0305     }
0306     m_ui->chkUseTCP->setChecked(dataMap[QLatin1String(NM_OPENVPN_KEY_PROTO_TCP)] == QLatin1String("yes"));
0307     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_DEV_TYPE))) {
0308         m_ui->chkUseVirtualDeviceType->setChecked(true);
0309         if (dataMap[QLatin1String(NM_OPENVPN_KEY_DEV_TYPE)] == QLatin1String("tap")) {
0310             m_ui->cmbDeviceType->setCurrentIndex(1);
0311         }
0312     }
0313     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_DEV))) {
0314         m_ui->chkUseVirtualDeviceName->setChecked(true);
0315         m_ui->leVirtualDeviceName->setText(dataMap[QLatin1String(NM_OPENVPN_KEY_DEV)]);
0316     }
0317     m_ui->chkMssRestrict->setChecked(dataMap[QLatin1String(NM_OPENVPN_KEY_MSSFIX)] == QLatin1String("yes"));
0318     m_ui->chkRandRemHosts->setChecked(dataMap[QLatin1String(NM_OPENVPN_KEY_REMOTE_RANDOM)] == QLatin1String("yes"));
0319 
0320     m_ui->chkIpv6TunLink->setChecked(dataMap[QLatin1String(NM_OPENVPN_KEY_TUN_IPV6)] == QLatin1String("yes"));
0321 
0322     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_PING))) {
0323         m_ui->chkPingInterval->setChecked(true);
0324         m_ui->sbPingInterval->setValue(dataMap[QLatin1String(NM_OPENVPN_KEY_PING)].toInt());
0325     }
0326 
0327     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_PING_EXIT)) || dataMap.contains(QLatin1String(NM_OPENVPN_KEY_PING_RESTART))) {
0328         m_ui->chkSpecifyExitRestartPing->setChecked(true);
0329         if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_PING_EXIT))) {
0330             m_ui->cbSpecifyExitRestartPing->setCurrentIndex(0); // Exit
0331             m_ui->sbSpecifyExitRestartPing->setValue(dataMap[QLatin1String(NM_OPENVPN_KEY_PING_EXIT)].toInt());
0332         } else {
0333             m_ui->cbSpecifyExitRestartPing->setCurrentIndex(1); // Restart
0334             m_ui->sbSpecifyExitRestartPing->setValue(dataMap[QLatin1String(NM_OPENVPN_KEY_PING_RESTART)].toInt());
0335         }
0336     }
0337 
0338     m_ui->chkAcceptAuthenticatedPackets->setChecked(dataMap[QLatin1String(NM_OPENVPN_KEY_FLOAT)] == QLatin1String("yes"));
0339 
0340     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_MAX_ROUTES))) {
0341         m_ui->chkMaxRoutes->setChecked(true);
0342         m_ui->sbMaxRoutes->setValue(dataMap[QLatin1String(NM_OPENVPN_KEY_MAX_ROUTES)].toInt());
0343     }
0344 
0345     // Optional Security Settings
0346     const QString hmacKeyAuth = dataMap[QLatin1String(NM_OPENVPN_KEY_AUTH)];
0347     if (hmacKeyAuth == QLatin1String(NM_OPENVPN_AUTH_NONE)) {
0348         m_ui->cboHmac->setCurrentIndex(Private::EnumHashingAlgorithms::None);
0349     } else if (hmacKeyAuth == QLatin1String(NM_OPENVPN_AUTH_RSA_MD4)) {
0350         m_ui->cboHmac->setCurrentIndex(Private::EnumHashingAlgorithms::Md4);
0351     } else if (hmacKeyAuth == QLatin1String(NM_OPENVPN_AUTH_MD5)) {
0352         m_ui->cboHmac->setCurrentIndex(Private::EnumHashingAlgorithms::Md5);
0353     } else if (hmacKeyAuth == QLatin1String(NM_OPENVPN_AUTH_SHA1)) {
0354         m_ui->cboHmac->setCurrentIndex(Private::EnumHashingAlgorithms::Sha1);
0355     } else if (hmacKeyAuth == QLatin1String(NM_OPENVPN_AUTH_SHA224)) {
0356         m_ui->cboHmac->setCurrentIndex(Private::EnumHashingAlgorithms::Sha224);
0357     } else if (hmacKeyAuth == QLatin1String(NM_OPENVPN_AUTH_SHA256)) {
0358         m_ui->cboHmac->setCurrentIndex(Private::EnumHashingAlgorithms::Sha256);
0359     } else if (hmacKeyAuth == QLatin1String(NM_OPENVPN_AUTH_SHA384)) {
0360         m_ui->cboHmac->setCurrentIndex(Private::EnumHashingAlgorithms::Sha384);
0361     } else if (hmacKeyAuth == QLatin1String(NM_OPENVPN_AUTH_SHA512)) {
0362         m_ui->cboHmac->setCurrentIndex(Private::EnumHashingAlgorithms::Sha512);
0363     } else if (hmacKeyAuth == QLatin1String(NM_OPENVPN_AUTH_RIPEMD160)) {
0364         m_ui->cboHmac->setCurrentIndex(Private::EnumHashingAlgorithms::Ripemd160);
0365     } else {
0366         m_ui->cboHmac->setCurrentIndex(Private::EnumHashingAlgorithms::Default);
0367     }
0368 
0369     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_KEYSIZE))) {
0370         m_ui->chkUseCustomCipherKey->setChecked(true);
0371         m_ui->sbCustomCipherKey->setValue(dataMap[QLatin1String(NM_OPENVPN_KEY_KEYSIZE)].toUInt());
0372     }
0373 
0374     // ciphers populated above?
0375     if (d->gotOpenVpnCiphers && dataMap.contains(QLatin1String(NM_OPENVPN_KEY_CIPHER))) {
0376         m_ui->cboCipher->setCurrentIndex(m_ui->cboCipher->findText(dataMap[QLatin1String(NM_OPENVPN_KEY_CIPHER)]));
0377     }
0378 
0379     // Optional TLS
0380     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_TLS_REMOTE))) {
0381         m_ui->cbCertCheck->setCurrentIndex(CertCheckType::VerifySubjectPartially);
0382         m_ui->subjectMatch->setText(dataMap[QLatin1String(NM_OPENVPN_KEY_TLS_REMOTE)]);
0383     }
0384 
0385     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_VERIFY_X509_NAME))) {
0386         const QString x509Value = dataMap.value(QLatin1String(NM_OPENVPN_KEY_VERIFY_X509_NAME));
0387         const QStringList x509List = x509Value.split(QLatin1Char(':'));
0388         if (x509List.size() == 2) {
0389             if (x509List.at(0) == QLatin1String(NM_OPENVPN_VERIFY_X509_NAME_TYPE_SUBJECT)) {
0390                 m_ui->cbCertCheck->setCurrentIndex(CertCheckType::VerifyWholeSubjectExactly);
0391             } else if (x509List.at(0) == QLatin1String(NM_OPENVPN_VERIFY_X509_NAME_TYPE_NAME)) {
0392                 m_ui->cbCertCheck->setCurrentIndex(CertCheckType::VerifyNameExactly);
0393             } else if (x509List.at(0) == QLatin1String(NM_OPENVPN_VERIFY_X509_NAME_TYPE_NAME_PREFIX)) {
0394                 m_ui->cbCertCheck->setCurrentIndex(CertCheckType::VerifyNameByPrefix);
0395             }
0396             m_ui->subjectMatch->setText(x509List.at(1));
0397         }
0398     } else {
0399         m_ui->cbCertCheck->setCurrentIndex(CertCheckType::DontVerify);
0400     }
0401 
0402     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_REMOTE_CERT_TLS))) {
0403         const QString remoteCertTls = dataMap[QLatin1String(NM_OPENVPN_KEY_REMOTE_CERT_TLS)];
0404         m_ui->chkRemoteCertTls->setChecked(true);
0405         m_ui->labelRemoteCertTls->setEnabled(true);
0406         m_ui->cmbRemoteCertTls->setEnabled(true);
0407         m_ui->cmbRemoteCertTls->setCurrentIndex(remoteCertTls == QLatin1String(NM_OPENVPN_REM_CERT_TLS_SERVER) ? 0 : 1);
0408     }
0409 
0410     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_NS_CERT_TYPE))) {
0411         const QString remoteCertTls = dataMap[QLatin1String(NM_OPENVPN_KEY_NS_CERT_TYPE)];
0412         m_ui->chkNsCertType->setChecked(true);
0413         m_ui->lblNsCertType->setEnabled(true);
0414         m_ui->cmbNsCertType->setEnabled(true);
0415         m_ui->cmbNsCertType->setCurrentIndex(remoteCertTls == QLatin1String(NM_OPENVPN_NS_CERT_TYPE_SERVER) ? 0 : 1);
0416     }
0417 
0418     const QString openvpnKeyTa = dataMap[QLatin1String(NM_OPENVPN_KEY_TA)];
0419     const QString openvpnKeyTlsCrypt = dataMap[QLatin1String(NM_OPENVPN_KEY_TLS_CRYPT)];
0420 
0421     if (!openvpnKeyTlsCrypt.isEmpty()) {
0422         m_ui->cboTLSMode->setCurrentIndex(2); // TLS-Crypt
0423         m_ui->kurlTlsAuthKey->setUrl(QUrl::fromLocalFile(openvpnKeyTlsCrypt));
0424     } else if (!openvpnKeyTa.isEmpty()) {
0425         m_ui->cboTLSMode->setCurrentIndex(1); // TLS-Auth
0426         m_ui->kurlTlsAuthKey->setUrl(QUrl::fromLocalFile(openvpnKeyTa));
0427         if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_TA_DIR))) {
0428             const uint tlsAuthDirection = dataMap[QLatin1String(NM_OPENVPN_KEY_TA_DIR)].toUInt();
0429             m_ui->cboDirection->setCurrentIndex(tlsAuthDirection + 1);
0430         }
0431     }
0432 
0433     // Proxies
0434     if (dataMap[QLatin1String(NM_OPENVPN_KEY_PROXY_TYPE)] == QLatin1String("http")) {
0435         m_ui->cmbProxyType->setCurrentIndex(Private::EnumProxyType::HTTP);
0436     } else if (dataMap[QLatin1String(NM_OPENVPN_KEY_PROXY_TYPE)] == QLatin1String("socks")) {
0437         m_ui->cmbProxyType->setCurrentIndex(Private::EnumProxyType::SOCKS);
0438     } else {
0439         m_ui->cmbProxyType->setCurrentIndex(Private::EnumProxyType::NotRequired);
0440     }
0441     proxyTypeChanged(m_ui->cmbProxyType->currentIndex());
0442     m_ui->proxyServerAddress->setText(dataMap[QLatin1String(NM_OPENVPN_KEY_PROXY_SERVER)]);
0443     if (dataMap.contains(QLatin1String(NM_OPENVPN_KEY_PROXY_PORT))) {
0444         m_ui->sbProxyPort->setValue(dataMap[QLatin1String(NM_OPENVPN_KEY_PROXY_PORT)].toUInt());
0445     } else {
0446         m_ui->sbProxyPort->setValue(0);
0447     }
0448     m_ui->chkProxyRetry->setChecked(dataMap[QLatin1String(NM_OPENVPN_KEY_PROXY_RETRY)] == QLatin1String("yes"));
0449     m_ui->proxyUsername->setText(dataMap[QLatin1String(NM_OPENVPN_KEY_HTTP_PROXY_USERNAME)]);
0450     d->readConfig = true;
0451 
0452     NetworkManager::Setting::SecretFlags type;
0453     type = (NetworkManager::Setting::SecretFlags)dataMap[NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD "-flags"].toInt();
0454     if (!(type & NetworkManager::Setting::NotSaved || type & NetworkManager::Setting::NotRequired)) {
0455         m_ui->proxyPassword->setText(secrets.value(QLatin1String(NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD)));
0456     }
0457     fillOnePasswordCombo(m_ui->proxyPassword, type);
0458 }
0459 
0460 void OpenVpnAdvancedWidget::fillOnePasswordCombo(PasswordField *passwordField, NetworkManager::Setting::SecretFlags type)
0461 {
0462     if (type.testFlag(NetworkManager::Setting::None)) {
0463         passwordField->setPasswordOption(PasswordField::StoreForAllUsers);
0464     } else if (type.testFlag(NetworkManager::Setting::AgentOwned)) {
0465         passwordField->setPasswordOption(PasswordField::StoreForUser);
0466     } else if (type.testFlag(NetworkManager::Setting::NotSaved)) {
0467         passwordField->setPasswordOption(PasswordField::AlwaysAsk);
0468     } else {
0469         passwordField->setPasswordOption(PasswordField::PasswordField::NotRequired);
0470     }
0471 }
0472 
0473 NetworkManager::VpnSetting::Ptr OpenVpnAdvancedWidget::setting() const
0474 {
0475     NMStringMap data;
0476     NMStringMap secretData;
0477 
0478     // optional settings
0479     if (m_ui->chkCustomPort->isChecked()) {
0480         data.insert(QLatin1String(NM_OPENVPN_KEY_PORT), QString::number(m_ui->sbCustomPort->value()));
0481     }
0482     if (m_ui->chkMtu->isChecked()) {
0483         data.insert(QLatin1String(NM_OPENVPN_KEY_TUNNEL_MTU), QString::number(m_ui->sbMtu->value()));
0484     }
0485     if (m_ui->chkCustomFragmentSize->isChecked()) {
0486         data.insert(QLatin1String(NM_OPENVPN_KEY_FRAGMENT_SIZE), QString::number(m_ui->sbCustomFragmentSize->value()));
0487     }
0488     if (m_ui->chkUseCustomReneg->isChecked()) {
0489         data.insert(QLatin1String(NM_OPENVPN_KEY_RENEG_SECONDS), QString::number(m_ui->sbCustomReneg->value()));
0490     }
0491     data.insert(QLatin1String(NM_OPENVPN_KEY_PROTO_TCP), m_ui->chkUseTCP->isChecked() ? QLatin1String("yes") : QLatin1String("no"));
0492 
0493     if (m_ui->chkUseCompression->isChecked()) {
0494         switch (m_ui->cmbUseCompression->currentIndex()) {
0495         case Private::EnumCompression::None:
0496             data.insert(QLatin1String(NM_OPENVPN_KEY_COMP_LZO), QLatin1String("no-by-default"));
0497             break;
0498         case Private::EnumCompression::LZO:
0499             data.insert(QLatin1String(NM_OPENVPN_KEY_COMPRESS), QLatin1String("lzo"));
0500             break;
0501         case Private::EnumCompression::LZ4:
0502             data.insert(QLatin1String(NM_OPENVPN_KEY_COMPRESS), QLatin1String("lz4"));
0503             break;
0504         case Private::EnumCompression::LZ4v2:
0505             data.insert(QLatin1String(NM_OPENVPN_KEY_COMPRESS), QLatin1String("lz4-v2"));
0506             break;
0507         case Private::EnumCompression::Adaptive:
0508             data.insert(QLatin1String(NM_OPENVPN_KEY_COMP_LZO), QLatin1String("adaptive"));
0509             break;
0510         case Private::EnumCompression::Automatic:
0511             data.insert(QLatin1String(NM_OPENVPN_KEY_COMPRESS), QLatin1String("yes"));
0512             break;
0513         }
0514     }
0515 
0516     if (m_ui->chkUseVirtualDeviceType->isChecked()) {
0517         data.insert(QLatin1String(NM_OPENVPN_KEY_DEV_TYPE), m_ui->cmbDeviceType->currentIndex() == 0 ? QLatin1String("tun") : QLatin1String("tap"));
0518     }
0519     if (m_ui->chkUseVirtualDeviceName->isChecked()) {
0520         data.insert(QLatin1String(NM_OPENVPN_KEY_DEV), m_ui->leVirtualDeviceName->text());
0521     }
0522 
0523     data.insert(QLatin1String(NM_OPENVPN_KEY_MSSFIX), m_ui->chkMssRestrict->isChecked() ? QLatin1String("yes") : QLatin1String("no"));
0524     data.insert(QLatin1String(NM_OPENVPN_KEY_REMOTE_RANDOM), m_ui->chkRandRemHosts->isChecked() ? QLatin1String("yes") : QLatin1String("no"));
0525     data.insert(QLatin1String(NM_OPENVPN_KEY_TUN_IPV6), m_ui->chkIpv6TunLink->isChecked() ? QLatin1String("yes") : QLatin1String("no"));
0526 
0527     if (m_ui->chkPingInterval->isChecked()) {
0528         data.insert(QLatin1String(NM_OPENVPN_KEY_PING), QString::number(m_ui->sbPingInterval->value()));
0529     }
0530 
0531     if (m_ui->chkSpecifyExitRestartPing->isChecked()) {
0532         if (m_ui->cbSpecifyExitRestartPing->currentIndex() == 0) { // Exit
0533             data.insert(QLatin1String(NM_OPENVPN_KEY_PING_EXIT), QString::number(m_ui->sbSpecifyExitRestartPing->value()));
0534         } else { // Restart
0535             data.insert(QLatin1String(NM_OPENVPN_KEY_PING_RESTART), QString::number(m_ui->sbSpecifyExitRestartPing->value()));
0536         }
0537     }
0538 
0539     data.insert(QLatin1String(NM_OPENVPN_KEY_FLOAT), m_ui->chkAcceptAuthenticatedPackets->isChecked() ? QLatin1String("yes") : QLatin1String("no"));
0540 
0541     if (m_ui->chkMaxRoutes->isChecked()) {
0542         data.insert(QLatin1String(NM_OPENVPN_KEY_MAX_ROUTES), QString::number(m_ui->sbMaxRoutes->value()));
0543     }
0544 
0545     // Optional Security
0546     switch (m_ui->cboHmac->currentIndex()) {
0547     case Private::EnumHashingAlgorithms::Default:
0548         break;
0549     case Private::EnumHashingAlgorithms::None:
0550         data.insert(QLatin1String(NM_OPENVPN_KEY_AUTH), QLatin1String(NM_OPENVPN_AUTH_NONE));
0551         break;
0552     case Private::EnumHashingAlgorithms::Md4:
0553         data.insert(QLatin1String(NM_OPENVPN_KEY_AUTH), QLatin1String(NM_OPENVPN_AUTH_RSA_MD4));
0554         break;
0555     case Private::EnumHashingAlgorithms::Md5:
0556         data.insert(QLatin1String(NM_OPENVPN_KEY_AUTH), QLatin1String(NM_OPENVPN_AUTH_MD5));
0557         break;
0558     case Private::EnumHashingAlgorithms::Sha1:
0559         data.insert(QLatin1String(NM_OPENVPN_KEY_AUTH), QLatin1String(NM_OPENVPN_AUTH_SHA1));
0560         break;
0561     case Private::EnumHashingAlgorithms::Sha224:
0562         data.insert(QLatin1String(NM_OPENVPN_KEY_AUTH), QLatin1String(NM_OPENVPN_AUTH_SHA224));
0563         break;
0564     case Private::EnumHashingAlgorithms::Sha256:
0565         data.insert(QLatin1String(NM_OPENVPN_KEY_AUTH), QLatin1String(NM_OPENVPN_AUTH_SHA256));
0566         break;
0567     case Private::EnumHashingAlgorithms::Sha384:
0568         data.insert(QLatin1String(NM_OPENVPN_KEY_AUTH), QLatin1String(NM_OPENVPN_AUTH_SHA384));
0569         break;
0570     case Private::EnumHashingAlgorithms::Sha512:
0571         data.insert(QLatin1String(NM_OPENVPN_KEY_AUTH), QLatin1String(NM_OPENVPN_AUTH_SHA512));
0572         break;
0573     case Private::EnumHashingAlgorithms::Ripemd160:
0574         data.insert(QLatin1String(NM_OPENVPN_KEY_AUTH), QLatin1String(NM_OPENVPN_AUTH_RIPEMD160));
0575         break;
0576     }
0577 
0578     if (m_ui->chkUseCustomCipherKey->isChecked()) {
0579         data.insert(QLatin1String(NM_OPENVPN_KEY_KEYSIZE), QString::number(m_ui->sbCustomCipherKey->value()));
0580     }
0581 
0582     if (m_ui->cboCipher->currentIndex() != 0) {
0583         data.insert(QLatin1String(NM_OPENVPN_KEY_CIPHER), m_ui->cboCipher->currentText());
0584     }
0585 
0586     // optional tls authentication
0587     switch (m_ui->cbCertCheck->currentIndex()) {
0588     case CertCheckType::DontVerify:
0589         break;
0590     case CertCheckType::VerifyWholeSubjectExactly:
0591         data.insert(QLatin1String(NM_OPENVPN_KEY_VERIFY_X509_NAME),
0592                     QStringLiteral("%1:%2").arg(NM_OPENVPN_VERIFY_X509_NAME_TYPE_SUBJECT, m_ui->subjectMatch->text()));
0593         break;
0594     case CertCheckType::VerifyNameExactly:
0595         data.insert(QLatin1String(NM_OPENVPN_KEY_VERIFY_X509_NAME),
0596                     QStringLiteral("%1:%2").arg(NM_OPENVPN_VERIFY_X509_NAME_TYPE_NAME, m_ui->subjectMatch->text()));
0597         break;
0598     case CertCheckType::VerifyNameByPrefix:
0599         data.insert(QLatin1String(NM_OPENVPN_KEY_VERIFY_X509_NAME),
0600                     QStringLiteral("%1:%2").arg(NM_OPENVPN_VERIFY_X509_NAME_TYPE_NAME_PREFIX, m_ui->subjectMatch->text()));
0601         break;
0602     case CertCheckType::VerifySubjectPartially:
0603         data.insert(QLatin1String(NM_OPENVPN_KEY_TLS_REMOTE), m_ui->subjectMatch->text());
0604         break;
0605     }
0606 
0607     if (m_ui->chkRemoteCertTls->isChecked()) {
0608         if (m_ui->cmbRemoteCertTls->currentIndex() == 0) {
0609             data.insert(QLatin1String(NM_OPENVPN_KEY_REMOTE_CERT_TLS), NM_OPENVPN_REM_CERT_TLS_SERVER);
0610         } else {
0611             data.insert(QLatin1String(NM_OPENVPN_KEY_REMOTE_CERT_TLS), NM_OPENVPN_REM_CERT_TLS_CLIENT);
0612         }
0613     }
0614 
0615     if (m_ui->chkNsCertType->isChecked()) {
0616         if (m_ui->cmbNsCertType->currentIndex() == 0) {
0617             data.insert(QLatin1String(NM_OPENVPN_KEY_NS_CERT_TYPE), NM_OPENVPN_NS_CERT_TYPE_SERVER);
0618         } else {
0619             data.insert(QLatin1String(NM_OPENVPN_KEY_NS_CERT_TYPE), NM_OPENVPN_NS_CERT_TYPE_CLIENT);
0620         }
0621     }
0622 
0623     if (m_ui->cboTLSMode->currentIndex() == 1) { // TLS-Auth
0624         QUrl tlsAuthKeyUrl = m_ui->kurlTlsAuthKey->url();
0625         if (!tlsAuthKeyUrl.isEmpty()) {
0626             data.insert(QLatin1String(NM_OPENVPN_KEY_TA), tlsAuthKeyUrl.path());
0627         }
0628         if (m_ui->cboDirection->currentIndex() > 0) {
0629             data.insert(QLatin1String(NM_OPENVPN_KEY_TA_DIR), QString::number(m_ui->cboDirection->currentIndex() - 1));
0630         }
0631     } else if (m_ui->cboTLSMode->currentIndex() == 2) { // TLS-Crypt
0632         QUrl tlsCryptKeyUrl = m_ui->kurlTlsAuthKey->url();
0633         if (!tlsCryptKeyUrl.isEmpty()) {
0634             data.insert(QLatin1String(NM_OPENVPN_KEY_TLS_CRYPT), tlsCryptKeyUrl.path());
0635         }
0636     }
0637 
0638     // Proxies
0639     switch (m_ui->cmbProxyType->currentIndex()) {
0640     case Private::EnumProxyType::NotRequired:
0641         break;
0642     case Private::EnumProxyType::HTTP:
0643         data.insert(QLatin1String(NM_OPENVPN_KEY_PROXY_TYPE), QLatin1String("http"));
0644         data.insert(QLatin1String(NM_OPENVPN_KEY_PROXY_SERVER), m_ui->proxyServerAddress->text());
0645         data.insert(QLatin1String(NM_OPENVPN_KEY_PROXY_PORT), QString::number(m_ui->sbProxyPort->value()));
0646         data.insert(QLatin1String(NM_OPENVPN_KEY_PROXY_RETRY), m_ui->chkProxyRetry->isChecked() ? QLatin1String("yes") : QLatin1String("no"));
0647         if (!m_ui->proxyUsername->text().isEmpty()) {
0648             data.insert(QLatin1String(NM_OPENVPN_KEY_HTTP_PROXY_USERNAME), m_ui->proxyUsername->text());
0649             secretData.insert(QLatin1String(NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD), m_ui->proxyPassword->text());
0650             handleOnePasswordType(m_ui->proxyPassword, QLatin1String(NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD "-flags"), data);
0651         }
0652         break;
0653     case Private::EnumProxyType::SOCKS:
0654         data.insert(QLatin1String(NM_OPENVPN_KEY_PROXY_TYPE), QLatin1String("socks"));
0655         data.insert(QLatin1String(NM_OPENVPN_KEY_PROXY_SERVER), m_ui->proxyServerAddress->text());
0656         data.insert(QLatin1String(NM_OPENVPN_KEY_PROXY_PORT), QString::number(m_ui->sbProxyPort->value()));
0657         data.insert(QLatin1String(NM_OPENVPN_KEY_PROXY_RETRY), m_ui->chkProxyRetry->isChecked() ? QLatin1String("yes") : QLatin1String("no"));
0658         break;
0659     }
0660 
0661     d->setting->setData(data);
0662     d->setting->setSecrets(secretData);
0663 
0664     return d->setting;
0665 }
0666 
0667 void OpenVpnAdvancedWidget::certCheckTypeChanged(int type)
0668 {
0669     if (type == CertCheckType::DontVerify) {
0670         m_ui->lbSubjectMatch->setEnabled(false);
0671         m_ui->subjectMatch->setEnabled(false);
0672     } else {
0673         m_ui->lbSubjectMatch->setEnabled(true);
0674         m_ui->subjectMatch->setEnabled(true);
0675     }
0676 }
0677 
0678 void OpenVpnAdvancedWidget::proxyTypeChanged(int type)
0679 {
0680     switch (type) {
0681     case Private::EnumProxyType::NotRequired:
0682         m_ui->proxyServerAddress->setEnabled(false);
0683         m_ui->sbProxyPort->setEnabled(false);
0684         m_ui->chkProxyRetry->setEnabled(false);
0685         m_ui->proxyUsername->setEnabled(false);
0686         m_ui->proxyPassword->setEnabled(false);
0687         break;
0688     case Private::EnumProxyType::HTTP:
0689         m_ui->proxyServerAddress->setEnabled(true);
0690         m_ui->sbProxyPort->setEnabled(true);
0691         m_ui->chkProxyRetry->setEnabled(true);
0692         m_ui->proxyUsername->setEnabled(true);
0693         m_ui->proxyPassword->setEnabled(true);
0694         break;
0695     case Private::EnumProxyType::SOCKS:
0696         m_ui->proxyServerAddress->setEnabled(true);
0697         m_ui->sbProxyPort->setEnabled(true);
0698         m_ui->chkProxyRetry->setEnabled(true);
0699         m_ui->proxyUsername->setEnabled(false);
0700         m_ui->proxyPassword->setEnabled(false);
0701         break;
0702     }
0703 }
0704 
0705 void OpenVpnAdvancedWidget::handleOnePasswordType(const PasswordField *passwordField, const QString &key, NMStringMap &data) const
0706 {
0707     const PasswordField::PasswordOption option = passwordField->passwordOption();
0708     switch (option) {
0709     case PasswordField::StoreForAllUsers:
0710         data.insert(key, QString::number(NetworkManager::Setting::None));
0711         break;
0712     case PasswordField::StoreForUser:
0713         data.insert(key, QString::number(NetworkManager::Setting::AgentOwned));
0714         break;
0715     case PasswordField::AlwaysAsk:
0716         data.insert(key, QString::number(NetworkManager::Setting::NotSaved));
0717         break;
0718     case PasswordField::NotRequired:
0719         data.insert(key, QString::number(NetworkManager::Setting::NotRequired));
0720         break;
0721     }
0722 }