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

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