File indexing completed on 2024-05-05 17:42:56

0001 /*
0002     SPDX-FileCopyrightText: 2008 Will Stephenson <wstephenson@kde.org>
0003     SPDX-FileCopyrightText: 2011-2012 Rajeesh K Nambiar <rajeeshknambiar@gmail.com>
0004     SPDX-FileCopyrightText: 2011-2012 Lamarque V. Souza <lamarque@kde.org>
0005     SPDX-FileCopyrightText: 2013 Lukas Tinkl <ltinkl@redhat.com>
0006 
0007     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0008 */
0009 
0010 #include "vpnc.h"
0011 #include "plasma_nm_vpnc.h"
0012 
0013 #include <QFile>
0014 #include <QFileInfo>
0015 #include <QStandardPaths>
0016 
0017 #include "nm-vpnc-service.h"
0018 #include <KLocalizedString>
0019 #include <KMessageBox>
0020 #include <KPluginFactory>
0021 #include <KSharedConfig>
0022 
0023 #include <NetworkManagerQt/Connection>
0024 #include <NetworkManagerQt/Ipv4Setting>
0025 #include <NetworkManagerQt/VpnSetting>
0026 
0027 #include <arpa/inet.h>
0028 
0029 #include "vpncauth.h"
0030 #include "vpncwidget.h"
0031 
0032 VpncUiPluginPrivate::VpncUiPluginPrivate()
0033 {
0034     decryptedPasswd.clear();
0035     ciscoDecrypt = nullptr;
0036 }
0037 
0038 VpncUiPluginPrivate::~VpncUiPluginPrivate() = default;
0039 
0040 QString VpncUiPluginPrivate::readStringKeyValue(const KConfigGroup &configGroup, const QString &key)
0041 {
0042     const QString retValue = configGroup.readEntry(key);
0043     if (retValue.isEmpty()) {
0044         // String key can also start with "!" in CISCO pcf file.
0045         return configGroup.readEntry('!' + key);
0046     } else {
0047         return retValue;
0048     }
0049 }
0050 
0051 void VpncUiPluginPrivate::gotCiscoDecryptOutput()
0052 {
0053     QByteArray output = ciscoDecrypt->readAll();
0054     if (!output.isEmpty()) {
0055         const QList<QByteArray> lines = output.split('\n');
0056         if (!lines.isEmpty()) {
0057             decryptedPasswd = QString::fromUtf8(lines.first());
0058         }
0059     }
0060 }
0061 
0062 void VpncUiPluginPrivate::ciscoDecryptFinished(int exitCode, QProcess::ExitStatus exitStatus)
0063 {
0064     if (exitCode || exitStatus != QProcess::NormalExit) {
0065         decryptedPasswd.clear();
0066     }
0067 }
0068 
0069 void VpncUiPluginPrivate::ciscoDecryptError(QProcess::ProcessError pError)
0070 {
0071     if (!pError) {
0072         qCWarning(PLASMA_NM_VPNC_LOG) << "Error in executing cisco-decrypt";
0073         KMessageBox::error(nullptr, i18n("Error decrypting the obfuscated password"), i18n("Error"), KMessageBox::Notify);
0074     }
0075     decryptedPasswd.clear();
0076 }
0077 
0078 #define NM_VPNC_LOCAL_PORT_DEFAULT 500
0079 
0080 K_PLUGIN_CLASS_WITH_JSON(VpncUiPlugin, "plasmanetworkmanagement_vpncui.json")
0081 
0082 VpncUiPlugin::VpncUiPlugin(QObject *parent, const QVariantList &)
0083     : VpnUiPlugin(parent)
0084 {
0085 }
0086 
0087 VpncUiPlugin::~VpncUiPlugin() = default;
0088 
0089 SettingWidget *VpncUiPlugin::widget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent)
0090 {
0091     return new VpncWidget(setting, parent);
0092 }
0093 
0094 SettingWidget *VpncUiPlugin::askUser(const NetworkManager::VpnSetting::Ptr &setting, const QStringList &hints, QWidget *parent)
0095 {
0096     return new VpncAuthDialog(setting, hints, parent);
0097 }
0098 
0099 QString VpncUiPlugin::suggestedFileName(const NetworkManager::ConnectionSettings::Ptr &connection) const
0100 {
0101     return connection->id() + QStringLiteral(".pcf");
0102 }
0103 
0104 QStringList VpncUiPlugin::supportedFileExtensions() const
0105 {
0106     return {QStringLiteral("*.pcf")};
0107 }
0108 
0109 VpnUiPlugin::ImportResult VpncUiPlugin::importConnectionSettings(const QString &fileName)
0110 {
0111     GError *error = nullptr;
0112 
0113     GSList *plugins = nm_vpn_plugin_info_list_load();
0114 
0115     NMVpnPluginInfo *plugin_info = nm_vpn_plugin_info_list_find_by_service(plugins, "org.freedesktop.NetworkManager.vpnc");
0116 
0117     if (!plugin_info) {
0118         return VpnUiPlugin::ImportResult::fail(i18n("NetworkManager is missing support for Cisco Compatible VPN"));
0119     }
0120 
0121     NMVpnEditorPlugin *plugin = nm_vpn_plugin_info_load_editor_plugin(plugin_info, &error);
0122 
0123     NMConnection *connection = nm_vpn_editor_plugin_import(plugin, fileName.toUtf8().constData(), &error);
0124 
0125     if (!connection) {
0126         const QString errorMessage = QString::fromUtf8(error->message);
0127         g_error_free(error);
0128 
0129         return VpnUiPlugin::ImportResult::fail(errorMessage);
0130     }
0131 
0132     return VpnUiPlugin::ImportResult::pass(connection);
0133 }
0134 
0135 VpncUiPlugin::ExportResult VpncUiPlugin::exportConnectionSettings(const NetworkManager::ConnectionSettings::Ptr &connection, const QString &fileName)
0136 {
0137     NMStringMap data;
0138     NMStringMap secretData;
0139 
0140     NetworkManager::VpnSetting::Ptr vpnSetting = connection->setting(NetworkManager::Setting::Vpn).dynamicCast<NetworkManager::VpnSetting>();
0141     data = vpnSetting->data();
0142     secretData = vpnSetting->secrets();
0143 
0144     KSharedConfig::Ptr config = KSharedConfig::openConfig(fileName);
0145     if (!config) {
0146         return VpnUiPlugin::ExportResult::fail(i18n("%1: file could not be created", fileName));
0147     }
0148     KConfigGroup cg(config, "main");
0149 
0150     cg.writeEntry("Description", connection->id());
0151     cg.writeEntry("Host", data.value(NM_VPNC_KEY_GATEWAY));
0152     if (data.value(NM_VPNC_KEY_AUTHMODE) == QLatin1String("hybrid")) {
0153         cg.writeEntry("AuthType", "5");
0154     } else {
0155         cg.writeEntry("AuthType", "1");
0156     }
0157     cg.writeEntry("GroupName", data.value(NM_VPNC_KEY_ID));
0158     cg.writeEntry("GroupPwd", secretData.value(NM_VPNC_KEY_SECRET));
0159     cg.writeEntry("UserPassword", secretData.value(NM_VPNC_KEY_XAUTH_PASSWORD));
0160     cg.writeEntry("enc_GroupPwd", "");
0161     cg.writeEntry("enc_UserPassword", "");
0162     if ((NetworkManager::Setting::SecretFlags)data.value(NM_VPNC_KEY_XAUTH_PASSWORD "-flags").toInt() & NetworkManager::Setting::NotSaved) {
0163         cg.writeEntry("SaveUserPassword", "0");
0164     }
0165     if ((NetworkManager::Setting::SecretFlags)data.value(NM_VPNC_KEY_XAUTH_PASSWORD "-flags").toInt() & NetworkManager::Setting::AgentOwned) {
0166         cg.writeEntry("SaveUserPassword", "1");
0167     }
0168     if ((NetworkManager::Setting::SecretFlags)data.value(NM_VPNC_KEY_XAUTH_PASSWORD "-flags").toInt() & NetworkManager::Setting::NotRequired) {
0169         cg.writeEntry("SaveUserPassword", "2");
0170     }
0171     cg.writeEntry("Username", data.value(NM_VPNC_KEY_XAUTH_USER));
0172     cg.writeEntry("EnableISPConnect", "0");
0173     cg.writeEntry("ISPConnectType", "0");
0174     cg.writeEntry("ISPConnect", "");
0175     cg.writeEntry("ISPCommand", "");
0176     cg.writeEntry("EnableBackup", "0");
0177     cg.writeEntry("BackupServer", "");
0178     cg.writeEntry("CertStore", "0");
0179     cg.writeEntry("CertName", "");
0180     cg.writeEntry("CertPath", "");
0181     cg.writeEntry("CertSubjectName", "");
0182     cg.writeEntry("CertSerialHash", "");
0183     cg.writeEntry("DHGroup", data.value(NM_VPNC_KEY_DHGROUP));
0184     cg.writeEntry("ForceKeepAlives", "0");
0185     cg.writeEntry("NTDomain", data.value(NM_VPNC_KEY_DOMAIN));
0186     cg.writeEntry("EnableMSLogon", "0");
0187     cg.writeEntry("MSLogonType", "0");
0188     cg.writeEntry("TunnelingMode", "0");
0189     cg.writeEntry("TcpTunnelingPort", "10000");
0190     cg.writeEntry("PeerTimeout", data.value(NM_VPNC_KEY_DPD_IDLE_TIMEOUT));
0191     cg.writeEntry("EnableLocalLAN", "1");
0192     cg.writeEntry("SendCertChain", "0");
0193     cg.writeEntry("VerifyCertDN", "");
0194     cg.writeEntry("EnableSplitDNS", "1");
0195     cg.writeEntry("SPPhonebook", "");
0196     if (data.value(NM_VPNC_KEY_SINGLE_DES) == "yes") {
0197         cg.writeEntry("SingleDES", "1");
0198     }
0199     if (data.value(NM_VPNC_KEY_NAT_TRAVERSAL_MODE) == NM_VPNC_NATT_MODE_CISCO) {
0200         cg.writeEntry("EnableNat", "1");
0201     }
0202     if (data.value(NM_VPNC_KEY_NAT_TRAVERSAL_MODE) == NM_VPNC_NATT_MODE_NATT) {
0203         cg.writeEntry("EnableNat", "1");
0204         cg.writeEntry("X-NM-Use-NAT-T", "1");
0205     }
0206     if (data.value(NM_VPNC_KEY_NAT_TRAVERSAL_MODE) == NM_VPNC_NATT_MODE_NATT_ALWAYS) {
0207         cg.writeEntry("EnableNat", "1");
0208         cg.writeEntry("X-NM-Force-NAT-T", "1");
0209     }
0210     // Export X-NM-Routes
0211     NetworkManager::Ipv4Setting::Ptr ipv4Setting = connection->setting(NetworkManager::Setting::Ipv4).dynamicCast<NetworkManager::Ipv4Setting>();
0212     if (!ipv4Setting->routes().isEmpty()) {
0213         QString routes;
0214         for (const NetworkManager::IpRoute &route : ipv4Setting->routes()) {
0215             routes += route.ip().toString() + QLatin1Char('/') + QString::number(route.prefixLength()) + QLatin1Char(' ');
0216         }
0217         cg.writeEntry("X-NM-Routes", routes.trimmed());
0218     }
0219 
0220     cg.sync();
0221 
0222     return VpnUiPlugin::ExportResult::pass();
0223 }
0224 
0225 #include "vpnc.moc"