File indexing completed on 2024-04-28 05:33:53

0001 /*
0002     SPDX-FileCopyrightText: 2013 Jan Grulich <jgrulich@redhat.com>
0003     SPDX-FileCopyrightText: 2013 Lukas Tinkl <ltinkl@redhat.com>
0004     SPDX-FileCopyrightText: 2013 Daniel Nicoletti <dantti12@gmail.com>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "secretagent.h"
0010 #include "passworddialog.h"
0011 
0012 #include "plasma_nm_kded.h"
0013 
0014 #include "configuration.h"
0015 
0016 #include <NetworkManagerQt/ConnectionSettings>
0017 #include <NetworkManagerQt/GenericTypes>
0018 #include <NetworkManagerQt/GsmSetting>
0019 #include <NetworkManagerQt/Security8021xSetting>
0020 #include <NetworkManagerQt/Settings>
0021 #include <NetworkManagerQt/VpnSetting>
0022 #include <NetworkManagerQt/WireguardSetting>
0023 #include <NetworkManagerQt/WirelessSecuritySetting>
0024 #include <NetworkManagerQt/WirelessSetting>
0025 
0026 #include <QDBusConnection>
0027 #include <QDialog>
0028 #include <QStringBuilder>
0029 
0030 #include <KConfig>
0031 #include <KConfigGroup>
0032 #include <KLocalizedString>
0033 #include <KPluginFactory>
0034 #include <KWallet>
0035 #include <KWindowSystem>
0036 #include <KX11Extras>
0037 
0038 SecretAgent::SecretAgent(QObject *parent)
0039     : NetworkManager::SecretAgent(QStringLiteral("org.kde.plasma.networkmanagement"), NetworkManager::SecretAgent::Capability::VpnHints, parent)
0040     , m_openWalletFailed(false)
0041     , m_wallet(nullptr)
0042     , m_dialog(nullptr)
0043 {
0044     connect(NetworkManager::notifier(), &NetworkManager::Notifier::serviceDisappeared, this, &SecretAgent::killDialogs);
0045 
0046     // We have to import secrets previously stored in plaintext files
0047     importSecretsFromPlainTextFiles();
0048 }
0049 
0050 SecretAgent::~SecretAgent() = default;
0051 
0052 NMVariantMapMap SecretAgent::GetSecrets(const NMVariantMapMap &connection,
0053                                         const QDBusObjectPath &connection_path,
0054                                         const QString &setting_name,
0055                                         const QStringList &hints,
0056                                         uint flags)
0057 {
0058     qCDebug(PLASMA_NM_KDED_LOG) << Q_FUNC_INFO;
0059     qCDebug(PLASMA_NM_KDED_LOG) << "Path:" << connection_path.path();
0060     qCDebug(PLASMA_NM_KDED_LOG) << "Setting name:" << setting_name;
0061     qCDebug(PLASMA_NM_KDED_LOG) << "Hints:" << hints;
0062     qCDebug(PLASMA_NM_KDED_LOG) << "Flags:" << flags;
0063 
0064     const QString callId = connection_path.path() % setting_name;
0065     for (const SecretsRequest &request : std::as_const(m_calls)) {
0066         if (request == callId) {
0067             qCWarning(PLASMA_NM_KDED_LOG) << "GetSecrets was called again! This should not happen, cancelling first call" << connection_path.path()
0068                                           << setting_name;
0069             CancelGetSecrets(connection_path, setting_name);
0070             break;
0071         }
0072     }
0073 
0074     setDelayedReply(true);
0075     SecretsRequest request(SecretsRequest::GetSecrets);
0076     request.callId = callId;
0077     request.connection = connection;
0078     request.connection_path = connection_path;
0079     request.flags = static_cast<NetworkManager::SecretAgent::GetSecretsFlags>(flags);
0080     request.hints = hints;
0081     request.setting_name = setting_name;
0082     request.message = message();
0083     m_calls << request;
0084 
0085     processNext();
0086 
0087     return {};
0088 }
0089 
0090 void SecretAgent::SaveSecrets(const NMVariantMapMap &connection, const QDBusObjectPath &connection_path)
0091 {
0092     qCDebug(PLASMA_NM_KDED_LOG) << Q_FUNC_INFO;
0093     qCDebug(PLASMA_NM_KDED_LOG) << "Path:" << connection_path.path();
0094     // qCDebug(PLASMA_NM_KDED_LOG) << "Setting:" << connection;
0095 
0096     setDelayedReply(true);
0097     SecretsRequest::Type type;
0098     if (hasSecrets(connection)) {
0099         type = SecretsRequest::SaveSecrets;
0100     } else {
0101         type = SecretsRequest::DeleteSecrets;
0102     }
0103     SecretsRequest request(type);
0104     request.connection = connection;
0105     request.connection_path = connection_path;
0106     request.message = message();
0107     m_calls << request;
0108 
0109     processNext();
0110 }
0111 
0112 void SecretAgent::DeleteSecrets(const NMVariantMapMap &connection, const QDBusObjectPath &connection_path)
0113 {
0114     qCDebug(PLASMA_NM_KDED_LOG) << Q_FUNC_INFO;
0115     qCDebug(PLASMA_NM_KDED_LOG) << "Path:" << connection_path.path();
0116     // qCDebug(PLASMA_NM_KDED_LOG) << "Setting:" << connection;
0117 
0118     setDelayedReply(true);
0119     SecretsRequest request(SecretsRequest::DeleteSecrets);
0120     request.connection = connection;
0121     request.connection_path = connection_path;
0122     request.message = message();
0123     m_calls << request;
0124 
0125     processNext();
0126 }
0127 
0128 void SecretAgent::CancelGetSecrets(const QDBusObjectPath &connection_path, const QString &setting_name)
0129 {
0130     qCDebug(PLASMA_NM_KDED_LOG) << Q_FUNC_INFO;
0131     qCDebug(PLASMA_NM_KDED_LOG) << "Path:" << connection_path.path();
0132     qCDebug(PLASMA_NM_KDED_LOG) << "Setting name:" << setting_name;
0133 
0134     QString callId = connection_path.path() % setting_name;
0135     for (int i = 0; i < m_calls.size(); ++i) {
0136         SecretsRequest request = m_calls.at(i);
0137         if (request.type == SecretsRequest::GetSecrets && callId == request.callId) {
0138             if (m_dialog == request.dialog) {
0139                 m_dialog = nullptr;
0140             }
0141             delete request.dialog;
0142             sendError(SecretAgent::AgentCanceled, QStringLiteral("Agent canceled the password dialog"), request.message);
0143             m_calls.removeAt(i);
0144             break;
0145         }
0146     }
0147 
0148     processNext();
0149 }
0150 
0151 void SecretAgent::dialogAccepted()
0152 {
0153     for (int i = 0; i < m_calls.size(); ++i) {
0154         SecretsRequest request = m_calls[i];
0155         if (request.type == SecretsRequest::GetSecrets && request.dialog == m_dialog) {
0156             NMStringMap tmpOpenconnectSecrets;
0157             NMVariantMapMap connection = request.dialog->secrets();
0158             if (connection.contains(QStringLiteral("vpn"))) {
0159                 if (connection.value(QStringLiteral("vpn")).contains(QStringLiteral("tmp-secrets"))) {
0160                     QVariantMap vpnSetting = connection.value(QStringLiteral("vpn"));
0161                     tmpOpenconnectSecrets = qdbus_cast<NMStringMap>(vpnSetting.take(QStringLiteral("tmp-secrets")));
0162                     connection.insert(QStringLiteral("vpn"), vpnSetting);
0163                 }
0164             }
0165 
0166             sendSecrets(connection, request.message);
0167             NetworkManager::ConnectionSettings::Ptr connectionSettings =
0168                 NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(connection));
0169             NetworkManager::ConnectionSettings::Ptr completeConnectionSettings;
0170             NetworkManager::Connection::Ptr con = NetworkManager::findConnectionByUuid(connectionSettings->uuid());
0171             if (con) {
0172                 completeConnectionSettings = con->settings();
0173             } else {
0174                 completeConnectionSettings = connectionSettings;
0175             }
0176             if (request.saveSecretsWithoutReply && completeConnectionSettings->connectionType() != NetworkManager::ConnectionSettings::Vpn) {
0177                 bool requestOffline = true;
0178                 if (completeConnectionSettings->connectionType() == NetworkManager::ConnectionSettings::Gsm) {
0179                     NetworkManager::GsmSetting::Ptr gsmSetting =
0180                         completeConnectionSettings->setting(NetworkManager::Setting::Gsm).staticCast<NetworkManager::GsmSetting>();
0181                     if (gsmSetting) {
0182                         if (gsmSetting->passwordFlags().testFlag(NetworkManager::Setting::NotSaved) //
0183                             || gsmSetting->passwordFlags().testFlag(NetworkManager::Setting::NotRequired)) {
0184                             requestOffline = false;
0185                         } else if (gsmSetting->pinFlags().testFlag(NetworkManager::Setting::NotSaved) //
0186                                    || gsmSetting->pinFlags().testFlag(NetworkManager::Setting::NotRequired)) {
0187                             requestOffline = false;
0188                         }
0189                     }
0190                 } else if (completeConnectionSettings->connectionType() == NetworkManager::ConnectionSettings::Wireless) {
0191                     NetworkManager::WirelessSecuritySetting::Ptr wirelessSecuritySetting =
0192                         completeConnectionSettings->setting(NetworkManager::Setting::WirelessSecurity).staticCast<NetworkManager::WirelessSecuritySetting>();
0193                     if (wirelessSecuritySetting
0194                         && ((wirelessSecuritySetting->keyMgmt() == NetworkManager::WirelessSecuritySetting::WpaEap)
0195                             || (wirelessSecuritySetting->keyMgmt() == NetworkManager::WirelessSecuritySetting::WpaEapSuiteB192))) {
0196                         NetworkManager::Security8021xSetting::Ptr security8021xSetting =
0197                             completeConnectionSettings->setting(NetworkManager::Setting::Security8021x).staticCast<NetworkManager::Security8021xSetting>();
0198                         if (security8021xSetting) {
0199                             if (security8021xSetting->eapMethods().contains(NetworkManager::Security8021xSetting::EapMethodFast) //
0200                                 || security8021xSetting->eapMethods().contains(NetworkManager::Security8021xSetting::EapMethodTtls) //
0201                                 || security8021xSetting->eapMethods().contains(NetworkManager::Security8021xSetting::EapMethodPeap)) {
0202                                 if (security8021xSetting->passwordFlags().testFlag(NetworkManager::Setting::NotSaved)
0203                                     || security8021xSetting->passwordFlags().testFlag(NetworkManager::Setting::NotRequired)) {
0204                                     requestOffline = false;
0205                                 }
0206                             }
0207                         }
0208                     }
0209                 }
0210 
0211                 if (requestOffline) {
0212                     SecretsRequest requestOffline(SecretsRequest::SaveSecrets);
0213                     requestOffline.connection = connection;
0214                     requestOffline.connection_path = request.connection_path;
0215                     requestOffline.saveSecretsWithoutReply = true;
0216                     m_calls << requestOffline;
0217                 }
0218             } else if (request.saveSecretsWithoutReply && completeConnectionSettings->connectionType() == NetworkManager::ConnectionSettings::Vpn
0219                        && !tmpOpenconnectSecrets.isEmpty()) {
0220                 NetworkManager::VpnSetting::Ptr vpnSetting =
0221                     completeConnectionSettings->setting(NetworkManager::Setting::Vpn).staticCast<NetworkManager::VpnSetting>();
0222                 if (vpnSetting) {
0223                     NMStringMap data = vpnSetting->data();
0224                     NMStringMap secrets = vpnSetting->secrets();
0225 
0226                     // Load secrets from auth dialog which are returned back to NM
0227                     if (connection.value(QStringLiteral("vpn")).contains(QStringLiteral("secrets"))) {
0228                         secrets.insert(qdbus_cast<NMStringMap>(connection.value(QStringLiteral("vpn")).value(QStringLiteral("secrets"))));
0229                     }
0230 
0231                     // Load temporary secrets from auth dialog which are not returned to NM
0232                     for (const QString &key : tmpOpenconnectSecrets.keys()) {
0233                         if (secrets.contains(QStringLiteral("save_passwords")) && secrets.value(QStringLiteral("save_passwords")) == QLatin1String("yes")) {
0234                             data.insert(key + QLatin1String("-flags"), QString::number(NetworkManager::Setting::AgentOwned));
0235                         } else {
0236                             data.insert(key + QLatin1String("-flags"), QString::number(NetworkManager::Setting::NotSaved));
0237                         }
0238                         secrets.insert(key, tmpOpenconnectSecrets.value(key));
0239                     }
0240 
0241                     vpnSetting->setData(data);
0242                     vpnSetting->setSecrets(secrets);
0243                     if (!con) {
0244                         con = NetworkManager::findConnection(request.connection_path.path());
0245                     }
0246 
0247                     if (con) {
0248                         con->update(completeConnectionSettings->toMap());
0249                     }
0250                 }
0251             }
0252 
0253             m_calls.removeAt(i);
0254             break;
0255         }
0256     }
0257 
0258     m_dialog->deleteLater();
0259     m_dialog = nullptr;
0260 
0261     processNext();
0262 }
0263 
0264 void SecretAgent::dialogRejected()
0265 {
0266     for (int i = 0; i < m_calls.size(); ++i) {
0267         SecretsRequest request = m_calls[i];
0268         if (request.type == SecretsRequest::GetSecrets && request.dialog == m_dialog) {
0269             sendError(SecretAgent::UserCanceled, QStringLiteral("User canceled the password dialog"), request.message);
0270             m_calls.removeAt(i);
0271             break;
0272         }
0273     }
0274 
0275     m_dialog->deleteLater();
0276     m_dialog = nullptr;
0277 
0278     processNext();
0279 }
0280 
0281 void SecretAgent::killDialogs()
0282 {
0283     int i = 0;
0284     while (i < m_calls.size()) {
0285         SecretsRequest request = m_calls[i];
0286         if (request.type == SecretsRequest::GetSecrets) {
0287             delete request.dialog;
0288             m_calls.removeAt(i);
0289         }
0290 
0291         ++i;
0292     }
0293 }
0294 
0295 void SecretAgent::walletOpened(bool success)
0296 {
0297     if (!success) {
0298         m_openWalletFailed = true;
0299         m_wallet->deleteLater();
0300         m_wallet = nullptr;
0301     } else {
0302         m_openWalletFailed = false;
0303     }
0304 
0305     processNext();
0306 }
0307 
0308 void SecretAgent::walletClosed()
0309 {
0310     if (m_wallet) {
0311         m_wallet->deleteLater();
0312     }
0313     m_wallet = nullptr;
0314 }
0315 
0316 void SecretAgent::processNext()
0317 {
0318     int i = 0;
0319     while (i < m_calls.size()) {
0320         SecretsRequest &request = m_calls[i];
0321         switch (request.type) {
0322         case SecretsRequest::GetSecrets:
0323             if (processGetSecrets(request)) {
0324                 m_calls.removeAt(i);
0325                 continue;
0326             }
0327             break;
0328         case SecretsRequest::SaveSecrets:
0329             if (processSaveSecrets(request)) {
0330                 m_calls.removeAt(i);
0331                 continue;
0332             }
0333             break;
0334         case SecretsRequest::DeleteSecrets:
0335             if (processDeleteSecrets(request)) {
0336                 m_calls.removeAt(i);
0337                 continue;
0338             }
0339             break;
0340         }
0341         ++i;
0342     }
0343 }
0344 
0345 bool SecretAgent::processGetSecrets(SecretsRequest &request) const
0346 {
0347     if (m_dialog) {
0348         return false;
0349     }
0350 
0351     NetworkManager::ConnectionSettings::Ptr connectionSettings =
0352         NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(request.connection));
0353     NetworkManager::Setting::Ptr setting = connectionSettings->setting(request.setting_name);
0354 
0355     const bool requestNew = request.flags & RequestNew;
0356     const bool userRequested = request.flags & UserRequested;
0357     const bool allowInteraction = request.flags & AllowInteraction;
0358     const bool isVpn = (setting->type() == NetworkManager::Setting::Vpn);
0359     const bool isWireGuard = (setting->type() == NetworkManager::Setting::WireGuard);
0360 
0361     if (isVpn) {
0362         NetworkManager::VpnSetting::Ptr vpnSetting = connectionSettings->setting(NetworkManager::Setting::Vpn).dynamicCast<NetworkManager::VpnSetting>();
0363         if (vpnSetting->serviceType() == QLatin1String("org.freedesktop.NetworkManager.ssh") && vpnSetting->data()["auth-type"] == QLatin1String("ssh-agent")) {
0364             QString authSock = qgetenv("SSH_AUTH_SOCK");
0365             qCDebug(PLASMA_NM_KDED_LOG) << Q_FUNC_INFO << "Sending SSH auth socket" << authSock;
0366 
0367             if (authSock.isEmpty()) {
0368                 sendError(SecretAgent::NoSecrets, QStringLiteral("SSH_AUTH_SOCK not present"), request.message);
0369             } else {
0370                 NMStringMap secrets;
0371                 secrets.insert(QStringLiteral("ssh-auth-sock"), authSock);
0372 
0373                 QVariantMap secretData;
0374                 secretData.insert(QStringLiteral("secrets"), QVariant::fromValue<NMStringMap>(secrets));
0375                 request.connection[request.setting_name] = secretData;
0376                 sendSecrets(request.connection, request.message);
0377             }
0378             return true;
0379         }
0380     }
0381 
0382     NMStringMap secretsMap;
0383     if (!requestNew && useWallet()) {
0384         if (m_wallet->isOpen()) {
0385             if (m_wallet->hasFolder(QStringLiteral("Network Management")) && m_wallet->setFolder(QStringLiteral("Network Management"))) {
0386                 QString key = QLatin1Char('{') % connectionSettings->uuid() % QLatin1Char('}') % QLatin1Char(';') % request.setting_name;
0387                 m_wallet->readMap(key, secretsMap);
0388             }
0389         } else {
0390             qCDebug(PLASMA_NM_KDED_LOG) << Q_FUNC_INFO << "Waiting for the wallet to open";
0391             return false;
0392         }
0393     }
0394 
0395     if (!secretsMap.isEmpty()) {
0396         setting->secretsFromStringMap(secretsMap);
0397         if (!(isVpn || isWireGuard) && setting->needSecrets(requestNew).isEmpty()) {
0398             // Enough secrets were retrieved from storage
0399             request.connection[request.setting_name] = setting->secretsToMap();
0400             sendSecrets(request.connection, request.message);
0401             return true;
0402         }
0403     }
0404 
0405     if (!Configuration::self().showPasswordDialog()) {
0406         sendError(SecretAgent::NoSecrets, QStringLiteral("Cannot authenticate"), request.message);
0407         Q_EMIT secretsError(request.connection_path.path(),
0408                             i18n("Authentication to %1 failed. Wrong password?", request.connection.value("connection").value("id").toString()));
0409         return true;
0410     } else if (isWireGuard && userRequested) { // Just return what we have
0411         NMVariantMapMap result;
0412         NetworkManager::WireGuardSetting::Ptr wireGuardSetting;
0413         wireGuardSetting = connectionSettings->setting(NetworkManager::Setting::WireGuard).dynamicCast<NetworkManager::WireGuardSetting>();
0414         // FIXME workaround when NM is asking for secrets which should be system-stored, if we send an empty map it
0415         // won't ask for additional secrets with AllowInteraction flag which would display the authentication dialog
0416         if (wireGuardSetting->secretsToMap().isEmpty()) {
0417             // Insert an empty secrets map as it was before I fixed it in NetworkManagerQt to make sure NM will ask again
0418             // with flags we need
0419             QVariantMap secretsMap;
0420             secretsMap.insert(QStringLiteral("secrets"), QVariant::fromValue<NMStringMap>(NMStringMap()));
0421             result.insert(QStringLiteral("wireguard"), secretsMap);
0422         } else {
0423             result.insert(QStringLiteral("wireguard"), wireGuardSetting->secretsToMap());
0424         }
0425         sendSecrets(result, request.message);
0426         return true;
0427     } else if (requestNew || (allowInteraction && !setting->needSecrets(requestNew).isEmpty()) || (allowInteraction && userRequested)
0428                || (isVpn && allowInteraction)) {
0429         m_dialog = new PasswordDialog(connectionSettings, request.flags, request.setting_name, request.hints);
0430         connect(m_dialog, &PasswordDialog::accepted, this, &SecretAgent::dialogAccepted);
0431         connect(m_dialog, &PasswordDialog::rejected, this, &SecretAgent::dialogRejected);
0432 
0433         if (m_dialog->hasError()) {
0434             sendError(m_dialog->error(), m_dialog->errorMessage(), request.message);
0435             delete m_dialog;
0436             m_dialog = nullptr;
0437             return true;
0438         } else {
0439             request.dialog = m_dialog;
0440             request.saveSecretsWithoutReply = !connectionSettings->permissions().isEmpty();
0441             m_dialog->show();
0442             if (KWindowSystem::isPlatformX11()) {
0443                 KX11Extras::setState(m_dialog->winId(), NET::KeepAbove);
0444             }
0445             return false;
0446         }
0447     } else if (isVpn && userRequested) { // just return what we have
0448         NMVariantMapMap result;
0449         NetworkManager::VpnSetting::Ptr vpnSetting;
0450         vpnSetting = connectionSettings->setting(NetworkManager::Setting::Vpn).dynamicCast<NetworkManager::VpnSetting>();
0451         // FIXME workaround when NM is asking for secrets which should be system-stored, if we send an empty map it
0452         // won't ask for additional secrets with AllowInteraction flag which would display the authentication dialog
0453         if (vpnSetting->secretsToMap().isEmpty()) {
0454             // Insert an empty secrets map as it was before I fixed it in NetworkManagerQt to make sure NM will ask again
0455             // with flags we need
0456             QVariantMap secretsMap;
0457             secretsMap.insert(QStringLiteral("secrets"), QVariant::fromValue<NMStringMap>(NMStringMap()));
0458             result.insert(QStringLiteral("vpn"), secretsMap);
0459         } else {
0460             result.insert(QStringLiteral("vpn"), vpnSetting->secretsToMap());
0461         }
0462         sendSecrets(result, request.message);
0463         return true;
0464     } else if (setting->needSecrets().isEmpty()) {
0465         NMVariantMapMap result;
0466         result.insert(setting->name(), setting->secretsToMap());
0467         sendSecrets(result, request.message);
0468         return true;
0469     } else {
0470         sendError(SecretAgent::InternalError, QStringLiteral("Plasma-nm did not know how to handle the request"), request.message);
0471         return true;
0472     }
0473 }
0474 
0475 bool SecretAgent::processSaveSecrets(SecretsRequest &request) const
0476 {
0477     if (useWallet()) {
0478         if (m_wallet->isOpen()) {
0479             NetworkManager::ConnectionSettings connectionSettings(request.connection);
0480 
0481             if (!m_wallet->hasFolder(QStringLiteral("Network Management"))) {
0482                 m_wallet->createFolder(QStringLiteral("Network Management"));
0483             }
0484 
0485             if (m_wallet->setFolder(QStringLiteral("Network Management"))) {
0486                 for (const NetworkManager::Setting::Ptr &setting : connectionSettings.settings()) {
0487                     NMStringMap secretsMap = setting->secretsToStringMap();
0488 
0489                     if (!secretsMap.isEmpty()) {
0490                         QString entryName = QLatin1Char('{') % connectionSettings.uuid() % QLatin1Char('}') % QLatin1Char(';') % setting->name();
0491                         m_wallet->writeMap(entryName, secretsMap);
0492                     }
0493                 }
0494             } else if (!request.saveSecretsWithoutReply) {
0495                 sendError(SecretAgent::InternalError, QStringLiteral("Could not store secrets in the wallet."), request.message);
0496                 return true;
0497             }
0498         } else {
0499             qCDebug(PLASMA_NM_KDED_LOG) << Q_FUNC_INFO << "Waiting for the wallet to open";
0500             return false;
0501         }
0502     }
0503 
0504     if (!request.saveSecretsWithoutReply) {
0505         QDBusMessage reply = request.message.createReply();
0506         if (!QDBusConnection::systemBus().send(reply)) {
0507             qCWarning(PLASMA_NM_KDED_LOG) << "Failed put save secrets reply into the queue";
0508         }
0509     }
0510 
0511     return true;
0512 }
0513 
0514 bool SecretAgent::processDeleteSecrets(SecretsRequest &request) const
0515 {
0516     if (useWallet()) {
0517         if (m_wallet->isOpen()) {
0518             if (m_wallet->hasFolder(QStringLiteral("Network Management")) && m_wallet->setFolder(QStringLiteral("Network Management"))) {
0519                 NetworkManager::ConnectionSettings connectionSettings(request.connection);
0520                 for (const NetworkManager::Setting::Ptr &setting : connectionSettings.settings()) {
0521                     QString entryName = QLatin1Char('{') % connectionSettings.uuid() % QLatin1Char('}') % QLatin1Char(';') % setting->name();
0522                     for (const QString &entry : m_wallet->entryList()) {
0523                         if (entry.startsWith(entryName)) {
0524                             m_wallet->removeEntry(entryName);
0525                         }
0526                     }
0527                 }
0528             }
0529         } else {
0530             qCDebug(PLASMA_NM_KDED_LOG) << Q_FUNC_INFO << "Waiting for the wallet to open";
0531             return false;
0532         }
0533     }
0534 
0535     QDBusMessage reply = request.message.createReply();
0536     if (!QDBusConnection::systemBus().send(reply)) {
0537         qCWarning(PLASMA_NM_KDED_LOG) << "Failed put delete secrets reply into the queue";
0538     }
0539 
0540     return true;
0541 }
0542 
0543 bool SecretAgent::useWallet() const
0544 {
0545     if (m_wallet) {
0546         return true;
0547     }
0548 
0549     /* If opening of KWallet failed before, we should not try to open it again and
0550      * we should return false instead */
0551     if (m_openWalletFailed) {
0552         m_openWalletFailed = false;
0553         return false;
0554     }
0555 
0556     if (KWallet::Wallet::isEnabled()) {
0557         m_wallet = KWallet::Wallet::openWallet(KWallet::Wallet::LocalWallet(), 0, KWallet::Wallet::Asynchronous);
0558         if (m_wallet) {
0559             connect(m_wallet, &KWallet::Wallet::walletOpened, this, &SecretAgent::walletOpened);
0560             connect(m_wallet, &KWallet::Wallet::walletClosed, this, &SecretAgent::walletClosed);
0561             return true;
0562         } else {
0563             qCWarning(PLASMA_NM_KDED_LOG) << "Error opening kwallet.";
0564         }
0565     } else if (m_wallet) {
0566         m_wallet->deleteLater();
0567         m_wallet = nullptr;
0568     }
0569 
0570     return false;
0571 }
0572 
0573 bool SecretAgent::hasSecrets(const NMVariantMapMap &connection) const
0574 {
0575     NetworkManager::ConnectionSettings connectionSettings(connection);
0576     for (const NetworkManager::Setting::Ptr &setting : connectionSettings.settings()) {
0577         if (!setting->secretsToMap().isEmpty()) {
0578             return true;
0579         }
0580     }
0581 
0582     return false;
0583 }
0584 
0585 void SecretAgent::sendSecrets(const NMVariantMapMap &secrets, const QDBusMessage &message) const
0586 {
0587     QDBusMessage reply;
0588     reply = message.createReply(QVariant::fromValue(secrets));
0589     if (!QDBusConnection::systemBus().send(reply)) {
0590         qCWarning(PLASMA_NM_KDED_LOG) << "Failed put the secret into the queue";
0591     }
0592 }
0593 
0594 void SecretAgent::importSecretsFromPlainTextFiles()
0595 {
0596     KConfig config(QStringLiteral("plasma-networkmanagement"), KConfig::SimpleConfig);
0597 
0598     // No action is required when the list of secrets is empty
0599     if (!config.groupList().isEmpty()) {
0600         for (const QString &groupName : config.groupList()) {
0601             QString loadedUuid = groupName.split(QLatin1Char(';')).first().remove('{').remove('}');
0602             QString loadedSettingType = groupName.split(QLatin1Char(';')).last();
0603             NetworkManager::Connection::Ptr connection = NetworkManager::findConnectionByUuid(loadedUuid);
0604             if (connection) {
0605                 NetworkManager::Setting::SecretFlags secretFlags =
0606                     KWallet::Wallet::isEnabled() ? NetworkManager::Setting::AgentOwned : NetworkManager::Setting::None;
0607                 QMap<QString, QString> secrets = config.entryMap(groupName);
0608                 NMVariantMapMap settings = connection->settings()->toMap();
0609 
0610                 for (const QString &setting : settings.keys()) {
0611                     if (setting == QLatin1String("vpn")) {
0612                         NetworkManager::VpnSetting::Ptr vpnSetting =
0613                             connection->settings()->setting(NetworkManager::Setting::Vpn).staticCast<NetworkManager::VpnSetting>();
0614                         if (vpnSetting) {
0615                             // Add loaded secrets from the config file
0616                             vpnSetting->secretsFromStringMap(secrets);
0617 
0618                             NMStringMap vpnData = vpnSetting->data();
0619                             // Reset flags, we can't save secrets to our secret agent when KWallet is not enabled, because
0620                             // we dropped support for plaintext files, therefore they need to be stored to NetworkManager
0621                             for (const QString &key : vpnData.keys()) {
0622                                 if (key.endsWith(QLatin1String("-flags"))) {
0623                                     vpnData.insert(key, QString::number((int)secretFlags));
0624                                 }
0625                             }
0626 
0627                             vpnSetting->setData(vpnData);
0628                             settings.insert(setting, vpnSetting->toMap());
0629                             connection->update(settings);
0630                         }
0631                     } else {
0632                         if (setting == loadedSettingType) {
0633                             QVariantMap tmpSetting = settings.value(setting);
0634                             // Reset flags, we can't save secrets to our secret agent when KWallet is not enabled, because
0635                             // we dropped support for plaintext files, therefore they need to be stored to NetworkManager
0636                             for (const QString &key : tmpSetting.keys()) {
0637                                 if (key.endsWith(QLatin1String("-flags"))) {
0638                                     tmpSetting.insert(key, (int)secretFlags);
0639                                 }
0640                             }
0641 
0642                             // Add loaded secrets from the config file
0643                             QMap<QString, QString>::const_iterator it = secrets.constBegin();
0644                             QMap<QString, QString>::const_iterator end = secrets.constEnd();
0645                             for (; it != end; ++it) {
0646                                 tmpSetting.insert(it.key(), it.value());
0647                             }
0648 
0649                             // Replace the old setting with the new one
0650                             settings.insert(setting, tmpSetting);
0651                             // Update the connection which re-saves secrets
0652                             connection->update(settings);
0653                         }
0654                     }
0655                 }
0656             }
0657 
0658             // Remove the group
0659             KConfigGroup group(&config, groupName);
0660             group.deleteGroup();
0661         }
0662     }
0663 }
0664 
0665 #include "moc_secretagent.cpp"