diff --git a/kcm/kcm.cpp b/kcm/kcm.cpp index 881c0855..346ea55b 100755 --- a/kcm/kcm.cpp +++ b/kcm/kcm.cpp @@ -1,571 +1,571 @@ /* Copyright 2016 Jan Grulich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "kcm.h" #include "debug.h" #include "connectioneditordialog.h" #include "mobileconnectionwizard.h" #include "uiutils.h" #include "vpnuiplugin.h" #include "settings/wireguardinterfacewidget.h" // KDE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Qt #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY(KCMNetworkConfigurationFactory, registerPlugin();) KCMNetworkmanagement::KCMNetworkmanagement(QWidget *parent, const QVariantList &args) : KCModule(parent, args) , m_handler(new Handler(this)) , m_tabWidget(nullptr) , m_ui(new Ui::KCMForm) { QWidget *mainWidget = new QWidget(this); m_ui->setupUi(mainWidget); KDeclarative::KDeclarative kdeclarative; kdeclarative.setDeclarativeEngine(m_ui->connectionView->engine()); kdeclarative.setTranslationDomain(QStringLiteral(TRANSLATION_DOMAIN)); kdeclarative.setupEngine(m_ui->connectionView->engine()); kdeclarative.setupContext(); m_ui->connectionView->setMinimumWidth(300); m_ui->connectionView->rootContext()->setContextProperty("alternateBaseColor", mainWidget->palette().color(QPalette::Active, QPalette::AlternateBase)); m_ui->connectionView->rootContext()->setContextProperty("backgroundColor", mainWidget->palette().color(QPalette::Active, QPalette::Window)); m_ui->connectionView->rootContext()->setContextProperty("baseColor", mainWidget->palette().color(QPalette::Active, QPalette::Base)); m_ui->connectionView->rootContext()->setContextProperty("highlightColor", mainWidget->palette().color(QPalette::Active, QPalette::Highlight)); m_ui->connectionView->rootContext()->setContextProperty("textColor", mainWidget->palette().color(QPalette::Active, QPalette::Text)); m_ui->connectionView->rootContext()->setContextProperty("connectionModified", false); m_ui->connectionView->setClearColor(Qt::transparent); m_ui->connectionView->setResizeMode(QQuickWidget::SizeRootObjectToView); m_ui->connectionView->setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kcm_networkmanagement/qml/main.qml")))); QObject *rootItem = m_ui->connectionView->rootObject(); connect(rootItem, SIGNAL(selectedConnectionChanged(QString)), this, SLOT(onSelectedConnectionChanged(QString))); connect(rootItem, SIGNAL(requestCreateConnection(int,QString,QString,bool)), this, SLOT(onRequestCreateConnection(int,QString,QString,bool))); connect(rootItem, SIGNAL(requestExportConnection(QString)), this, SLOT(onRequestExportConnection(QString))); connect(rootItem, SIGNAL(requestToChangeConnection(QString,QString)), this, SLOT(onRequestToChangeConnection(QString,QString))); QVBoxLayout *l = new QVBoxLayout(this); l->addWidget(mainWidget); setButtons(Button::Apply); NetworkManager::Connection::Ptr selectedConnection; // Look in the arguments for a connection ID to preselect - static const QLatin1Literal uuidArgumentMarker { "Uuid=" }; + static const QLatin1String uuidArgumentMarker { "Uuid=" }; for (QVariant arg : args) { if (arg.canConvert(QMetaType::QString)) { QString uuid = arg.toString(); if (uuid.startsWith(uuidArgumentMarker)) { uuid = uuid.replace(uuidArgumentMarker, QString()); selectedConnection = NetworkManager::findConnectionByUuid(uuid); qDebug() << "Selecting user connection:" << uuid; break; } } } // Pre-select the currently active primary connection if (!selectedConnection || !selectedConnection->isValid()) { NetworkManager::ActiveConnection::Ptr activeConnection = NetworkManager::primaryConnection(); if (activeConnection && activeConnection->isValid()) { selectedConnection = activeConnection->connection(); qDebug() << "Selecting active connection:" << selectedConnection->uuid(); } } // Select the very first connection as a fallback if (!selectedConnection || !selectedConnection->isValid()) { NetworkManager::Connection::List connectionList = NetworkManager::listConnections(); std::sort(connectionList.begin(), connectionList.end(), [] (const NetworkManager::Connection::Ptr &left, const NetworkManager::Connection::Ptr &right) { const QString leftName = left->settings()->id(); const UiUtils::SortedConnectionType leftType = UiUtils::connectionTypeToSortedType(left->settings()->connectionType()); const QDateTime leftDate = left->settings()->timestamp(); const QString rightName = right->settings()->id(); const UiUtils::SortedConnectionType rightType = UiUtils::connectionTypeToSortedType(right->settings()->connectionType()); const QDateTime rightDate = right->settings()->timestamp(); if (leftType < rightType) { return true; } else if (leftType > rightType) { return false; } if (leftDate > rightDate) { return true; } else if (leftDate < rightDate) { return false; } if (QString::localeAwareCompare(leftName, rightName) > 0) { return true; } else { return false; } }); for (const NetworkManager::Connection::Ptr &connection : connectionList) { const NetworkManager::ConnectionSettings::ConnectionType type = connection->settings()->connectionType(); if (UiUtils::isConnectionTypeSupported(type)) { selectedConnection = connection; qDebug() << "Selecting first connection:" << connection->uuid(); break; } } } if (selectedConnection && selectedConnection->isValid()) { const NetworkManager::ConnectionSettings::Ptr settings = selectedConnection->settings(); if (UiUtils::isConnectionTypeSupported(settings->connectionType())) { QMetaObject::invokeMethod(rootItem, "selectConnection", Q_ARG(QVariant, settings->id()), Q_ARG(QVariant, selectedConnection->path())); } } else { qDebug() << "Cannot preselect a connection"; } connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionAdded, this, &KCMNetworkmanagement::onConnectionAdded, Qt::UniqueConnection); // Initialize first scan and then scan every 15 seconds m_handler->requestScan(); m_timer = new QTimer(this); m_timer->setInterval(15000); connect(m_timer, &QTimer::timeout, [this] () { m_handler->requestScan(); }); m_timer->start(); } KCMNetworkmanagement::~KCMNetworkmanagement() { delete m_handler; if (m_tabWidget) { delete m_tabWidget; } delete m_ui; } void KCMNetworkmanagement::defaults() { KCModule::defaults(); } void KCMNetworkmanagement::load() { // If there is no loaded connection do nothing if (m_currentConnectionPath.isEmpty()) { return; } NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(m_currentConnectionPath); if (connection) { NetworkManager::ConnectionSettings::Ptr connectionSettings = connection->settings(); // Re-load the connection again to load stored values if (m_tabWidget) { m_tabWidget->setConnection(connectionSettings); } } KCModule::load(); } void KCMNetworkmanagement::save() { NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(m_currentConnectionPath); if (connection) { m_handler->updateConnection(connection, m_tabWidget->setting()); } kcmChanged(false); KCModule::save(); } void KCMNetworkmanagement::onConnectionAdded(const QString &connection) { if (m_createdConnectionUuid.isEmpty()) { return; } NetworkManager::Connection::Ptr newConnection = NetworkManager::findConnection(connection); if (newConnection) { NetworkManager::ConnectionSettings::Ptr connectionSettings = newConnection->settings(); if (connectionSettings && connectionSettings->uuid() == m_createdConnectionUuid) { QObject *rootItem = m_ui->connectionView->rootObject(); loadConnectionSettings(connectionSettings); QMetaObject::invokeMethod(rootItem, "selectConnection", Q_ARG(QVariant, connectionSettings->id()), Q_ARG(QVariant, newConnection->path())); m_createdConnectionUuid.clear(); } } } void KCMNetworkmanagement::onRequestCreateConnection(int connectionType, const QString &vpnType, const QString &specificType, bool shared) { NetworkManager::ConnectionSettings::ConnectionType type = static_cast(connectionType); if (type == NetworkManager::ConnectionSettings::Vpn && vpnType == "imported") { importVpn(); } else if (type == NetworkManager::ConnectionSettings::Gsm) { // launch the mobile broadband wizard, both gsm/cdma #if WITH_MODEMMANAGER_SUPPORT QPointer wizard = new MobileConnectionWizard(NetworkManager::ConnectionSettings::Unknown, this); connect(wizard.data(), &MobileConnectionWizard::accepted, [wizard, this] () { if (wizard->getError() == MobileProviders::Success) { qCDebug(PLASMA_NM) << "Mobile broadband wizard finished:" << wizard->type() << wizard->args(); if (wizard->args().count() == 2) { QVariantMap tmp = qdbus_cast(wizard->args().value(1)); NetworkManager::ConnectionSettings::Ptr connectionSettings; connectionSettings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(wizard->type())); connectionSettings->setId(wizard->args().value(0).toString()); if (wizard->type() == NetworkManager::ConnectionSettings::Gsm) { NetworkManager::GsmSetting::Ptr gsmSetting = connectionSettings->setting(NetworkManager::Setting::Gsm).staticCast(); gsmSetting->fromMap(tmp); gsmSetting->setPasswordFlags(NetworkManager::Setting::NotRequired); gsmSetting->setPinFlags(NetworkManager::Setting::NotRequired); } else if (wizard->type() == NetworkManager::ConnectionSettings::Cdma) { connectionSettings->setting(NetworkManager::Setting::Cdma)->fromMap(tmp); } else { qCWarning(PLASMA_NM) << Q_FUNC_INFO << "Unhandled setting type"; } // Generate new UUID connectionSettings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); addConnection(connectionSettings); } else { qCWarning(PLASMA_NM) << Q_FUNC_INFO << "Unexpected number of args to parse"; } } }); connect(wizard.data(), &MobileConnectionWizard::finished, [wizard] () { if (wizard) { wizard->deleteLater(); } }); wizard->setModal(true); wizard->show(); #endif } else { NetworkManager::ConnectionSettings::Ptr connectionSettings; connectionSettings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(type)); if (type == NetworkManager::ConnectionSettings::Vpn) { NetworkManager::VpnSetting::Ptr vpnSetting = connectionSettings->setting(NetworkManager::Setting::Vpn).dynamicCast(); vpnSetting->setServiceType(vpnType); // Set VPN subtype in case of Openconnect to add support for juniper if (vpnType == QLatin1String("org.freedesktop.NetworkManager.openconnect")) { NMStringMap data = vpnSetting->data(); data.insert(QLatin1String("protocol"), specificType); vpnSetting->setData(data); } } if (type == NetworkManager::ConnectionSettings::Wired || type == NetworkManager::ConnectionSettings::Wireless) { // Set auto-negotiate to true, NM sets it to false by default, but we used to have this before and also // I don't think it's wise to request users to specify speed and duplex as most of them don't know what is that // and what to set if (type == NetworkManager::ConnectionSettings::Wired) { NetworkManager::WiredSetting::Ptr wiredSetting = connectionSettings->setting(NetworkManager::Setting::Wired).dynamicCast(); wiredSetting->setAutoNegotiate(true); } if (shared) { if (type == NetworkManager::ConnectionSettings::Wireless) { NetworkManager::WirelessSetting::Ptr wifiSetting = connectionSettings->setting(NetworkManager::Setting::Wireless).dynamicCast(); wifiSetting->setMode(NetworkManager::WirelessSetting::Adhoc); wifiSetting->setSsid(i18n("my_shared_connection").toUtf8()); for (const NetworkManager::Device::Ptr & device : NetworkManager::networkInterfaces()) { if (device->type() == NetworkManager::Device::Wifi) { NetworkManager::WirelessDevice::Ptr wifiDev = device.objectCast(); if (wifiDev) { if (wifiDev->wirelessCapabilities().testFlag(NetworkManager::WirelessDevice::ApCap)) { wifiSetting->setMode(NetworkManager::WirelessSetting::Ap); wifiSetting->setMacAddress(NetworkManager::macAddressFromString(wifiDev->permanentHardwareAddress())); } } } } } NetworkManager::Ipv4Setting::Ptr ipv4Setting = connectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast(); ipv4Setting->setMethod(NetworkManager::Ipv4Setting::Shared); connectionSettings->setAutoconnect(false); } } if (type == NetworkManager::ConnectionSettings::WireGuard) { NetworkManager::WireGuardSetting::Ptr wireguardSetting = connectionSettings->setting(NetworkManager::Setting::WireGuard).dynamicCast(); NetworkManager::Ipv4Setting::Ptr ipv4Setting = connectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast(); NetworkManager::Ipv6Setting::Ptr ipv6Setting = connectionSettings->setting(NetworkManager::Setting::Ipv6).dynamicCast(); connectionSettings->setAutoconnect(false); ipv4Setting->setMethod(NetworkManager::Ipv4Setting::Disabled); ipv6Setting->setMethod(NetworkManager::Ipv6Setting::Ignored); } // Generate new UUID connectionSettings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); addConnection(connectionSettings); } } void KCMNetworkmanagement::onRequestExportConnection(const QString &connectionPath) { NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(connectionPath); if (!connection) { return; } NetworkManager::ConnectionSettings::Ptr connSettings = connection->settings(); if (connSettings->connectionType() != NetworkManager::ConnectionSettings::Vpn) return; NetworkManager::VpnSetting::Ptr vpnSetting = connSettings->setting(NetworkManager::Setting::Vpn).dynamicCast(); qCDebug(PLASMA_NM) << "Exporting VPN connection" << connection->name() << "type:" << vpnSetting->serviceType(); QString error; VpnUiPlugin * vpnPlugin = KServiceTypeTrader::createInstanceFromQuery(QStringLiteral("PlasmaNetworkManagement/VpnUiPlugin"), QStringLiteral("[X-NetworkManager-Services]=='%1'").arg(vpnSetting->serviceType()), this, QVariantList(), &error); if (vpnPlugin) { if (vpnPlugin->suggestedFileName(connSettings).isEmpty()) { // this VPN doesn't support export qCWarning(PLASMA_NM) << "This VPN doesn't support export"; return; } const QString url = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator() + vpnPlugin->suggestedFileName(connSettings); const QString filename = QFileDialog::getSaveFileName(this, i18n("Export VPN Connection"), url, vpnPlugin->supportedFileExtensions()); if (!filename.isEmpty()) { if (!vpnPlugin->exportConnectionSettings(connSettings, filename)) { // TODO display failure qCWarning(PLASMA_NM) << "Failed to export VPN connection"; } else { // TODO display success } } delete vpnPlugin; } else { qCWarning(PLASMA_NM) << "Error getting VpnUiPlugin for export:" << error; } } void KCMNetworkmanagement::onRequestToChangeConnection( const QString &connectionName, const QString &connectionPath) { NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(m_currentConnectionPath); if (connection) { if (KMessageBox::questionYesNo(this, i18n("Do you want to save changes made to the connection '%1'?", connection->name()), i18nc("@title:window", "Save Changes"), KStandardGuiItem::save(), KStandardGuiItem::discard(), QString(), KMessageBox::Notify) == KMessageBox::Yes) { save(); } } QObject *rootItem = m_ui->connectionView->rootObject(); QMetaObject::invokeMethod(rootItem, "selectConnection", Q_ARG(QVariant, connectionName), Q_ARG(QVariant, connectionPath)); } void KCMNetworkmanagement::onSelectedConnectionChanged(const QString &connectionPath) { if (connectionPath.isEmpty()) { resetSelection(); return; } m_currentConnectionPath = connectionPath; NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(m_currentConnectionPath); if (connection) { NetworkManager::ConnectionSettings::Ptr connectionSettings = connection->settings(); loadConnectionSettings(connectionSettings); } } void KCMNetworkmanagement::addConnection(const NetworkManager::ConnectionSettings::Ptr &connectionSettings) { QPointer editor = new ConnectionEditorDialog(connectionSettings); connect(editor.data(), &ConnectionEditorDialog::accepted, [connectionSettings, editor, this] () { // We got confirmation so watch this connection and select it once it is created m_createdConnectionUuid = connectionSettings->uuid(); m_handler->addConnection(editor->setting()); }); connect(editor.data(), &ConnectionEditorDialog::finished, [editor] () { if (editor) { editor->deleteLater(); } }); editor->setModal(true); editor->show(); } void KCMNetworkmanagement::kcmChanged(bool kcmChanged) { m_ui->connectionView->rootContext()->setContextProperty("connectionModified", kcmChanged); Q_EMIT changed(kcmChanged); } void KCMNetworkmanagement::loadConnectionSettings(const NetworkManager::ConnectionSettings::Ptr& connectionSettings) { if (m_tabWidget) { m_tabWidget->setConnection(connectionSettings); } else { m_tabWidget = new ConnectionEditorTabWidget(connectionSettings); connect(m_tabWidget, &ConnectionEditorTabWidget::settingChanged, [this] () { if (m_tabWidget->isInitialized() && m_tabWidget->isValid()) { kcmChanged(true); } }); connect(m_tabWidget, &ConnectionEditorTabWidget::validityChanged, [this] (bool valid) { if (m_tabWidget->isInitialized() && m_tabWidget->isValid() != valid) { kcmChanged(valid); } }); QVBoxLayout *layout = new QVBoxLayout(m_ui->connectionConfiguration); layout->addWidget(m_tabWidget); } kcmChanged(false); } void KCMNetworkmanagement::importVpn() { // get the list of supported extensions const KService::List services = KServiceTypeTrader::self()->query("PlasmaNetworkManagement/VpnUiPlugin"); QString extensions; for (const KService::Ptr &service : services) { VpnUiPlugin * vpnPlugin = service->createInstance(this); if (vpnPlugin) { extensions += vpnPlugin->supportedFileExtensions() % QStringLiteral(" "); delete vpnPlugin; } } const QString &filename = QFileDialog::getOpenFileName(this, i18n("Import VPN Connection"), QDir::homePath(), extensions.simplified()); if (!filename.isEmpty()) { const KService::List services = KServiceTypeTrader::self()->query("PlasmaNetworkManagement/VpnUiPlugin"); QFileInfo fi(filename); const QString ext = QStringLiteral("*.") % fi.suffix(); qCDebug(PLASMA_NM) << "Importing VPN connection " << filename << "extension:" << ext; // Handle WireGuard separately because it is different than all the other VPNs if (WireGuardInterfaceWidget::supportedFileExtensions().contains(ext)) { NMVariantMapMap connection = WireGuardInterfaceWidget::importConnectionSettings(filename); NetworkManager::ConnectionSettings connectionSettings; connectionSettings.fromMap(connection); connectionSettings.setUuid(NetworkManager::ConnectionSettings::createNewUuid()); // qCDebug(PLASMA_NM) << "Converted connection:" << connectionSettings; m_handler->addConnection(connectionSettings.toMap()); // qCDebug(PLASMA_NM) << "Adding imported connection under id:" << conId; if (!connection.isEmpty()) { return; // get out if the import produced at least some output } } for (const KService::Ptr &service : services) { VpnUiPlugin * vpnPlugin = service->createInstance(this); if (vpnPlugin && vpnPlugin->supportedFileExtensions().contains(ext)) { qCDebug(PLASMA_NM) << "Found VPN plugin" << service->name() << ", type:" << service->property("X-NetworkManager-Services", QVariant::String).toString(); NMVariantMapMap connection = vpnPlugin->importConnectionSettings(filename); // qCDebug(PLASMA_NM) << "Raw connection:" << connection; NetworkManager::ConnectionSettings connectionSettings; connectionSettings.fromMap(connection); connectionSettings.setUuid(NetworkManager::ConnectionSettings::createNewUuid()); // qCDebug(PLASMA_NM) << "Converted connection:" << connectionSettings; m_handler->addConnection(connectionSettings.toMap()); // qCDebug(PLASMA_NM) << "Adding imported connection under id:" << conId; if (connection.isEmpty()) { // the "positive" part will arrive with connectionAdded // TODO display success } else { delete vpnPlugin; break; // stop iterating over the plugins if the import produced at least some output } delete vpnPlugin; } } } } void KCMNetworkmanagement::resetSelection() { // Reset selected connections m_currentConnectionPath.clear(); QObject *rootItem = m_ui->connectionView->rootObject(); QMetaObject::invokeMethod(rootItem, "deselectConnections"); if (m_tabWidget) { delete m_ui->connectionConfiguration->layout(); delete m_tabWidget; m_tabWidget = nullptr; } Q_EMIT changed(false); } #include "kcm.moc" diff --git a/kded/secretagent.cpp b/kded/secretagent.cpp index 175115d7..a49e3a54 100644 --- a/kded/secretagent.cpp +++ b/kded/secretagent.cpp @@ -1,672 +1,672 @@ /* Copyright 2013 Jan Grulich Copyright 2013 Lukas Tinkl Copyright 2013 by Daniel Nicoletti This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "passworddialog.h" #include "secretagent.h" #include "debug.h" #include "configuration.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SecretAgent::SecretAgent(QObject* parent) : NetworkManager::SecretAgent("org.kde.plasma.networkmanagement", parent) , m_openWalletFailed(false) , m_wallet(nullptr) , m_dialog(nullptr) { connect(NetworkManager::notifier(), &NetworkManager::Notifier::serviceDisappeared, this, &SecretAgent::killDialogs); // We have to import secrets previously stored in plaintext files importSecretsFromPlainTextFiles(); } SecretAgent::~SecretAgent() { } NMVariantMapMap SecretAgent::GetSecrets(const NMVariantMapMap &connection, const QDBusObjectPath &connection_path, const QString &setting_name, const QStringList &hints, uint flags) { qCDebug(PLASMA_NM) << Q_FUNC_INFO; qCDebug(PLASMA_NM) << "Path:" << connection_path.path(); qCDebug(PLASMA_NM) << "Setting name:" << setting_name; qCDebug(PLASMA_NM) << "Hints:" << hints; qCDebug(PLASMA_NM) << "Flags:" << flags; const QString callId = connection_path.path() % setting_name; for (const SecretsRequest &request : m_calls) { if (request == callId) { qCWarning(PLASMA_NM) << "GetSecrets was called again! This should not happen, cancelling first call" << connection_path.path() << setting_name; CancelGetSecrets(connection_path, setting_name); break; } } setDelayedReply(true); SecretsRequest request(SecretsRequest::GetSecrets); request.callId = callId; request.connection = connection; request.connection_path = connection_path; request.flags = static_cast(flags); request.hints = hints; request.setting_name = setting_name; request.message = message(); m_calls << request; processNext(); return NMVariantMapMap(); } void SecretAgent::SaveSecrets(const NMVariantMapMap &connection, const QDBusObjectPath &connection_path) { qCDebug(PLASMA_NM) << Q_FUNC_INFO; qCDebug(PLASMA_NM) << "Path:" << connection_path.path(); // qCDebug(PLASMA_NM) << "Setting:" << connection; setDelayedReply(true); SecretsRequest::Type type; if (hasSecrets(connection)) { type = SecretsRequest::SaveSecrets; } else { type = SecretsRequest::DeleteSecrets; } SecretsRequest request(type); request.connection = connection; request.connection_path = connection_path; request.message = message(); m_calls << request; processNext(); } void SecretAgent::DeleteSecrets(const NMVariantMapMap &connection, const QDBusObjectPath &connection_path) { qCDebug(PLASMA_NM) << Q_FUNC_INFO; qCDebug(PLASMA_NM) << "Path:" << connection_path.path(); // qCDebug(PLASMA_NM) << "Setting:" << connection; setDelayedReply(true); SecretsRequest request(SecretsRequest::DeleteSecrets); request.connection = connection; request.connection_path = connection_path; request.message = message(); m_calls << request; processNext(); } void SecretAgent::CancelGetSecrets(const QDBusObjectPath &connection_path, const QString &setting_name) { qCDebug(PLASMA_NM) << Q_FUNC_INFO; qCDebug(PLASMA_NM) << "Path:" << connection_path.path(); qCDebug(PLASMA_NM) << "Setting name:" << setting_name; QString callId = connection_path.path() % setting_name; for (int i = 0; i < m_calls.size(); ++i) { SecretsRequest request = m_calls.at(i); if (request.type == SecretsRequest::GetSecrets && callId == request.callId) { if (m_dialog == request.dialog) { m_dialog = nullptr; } delete request.dialog; sendError(SecretAgent::AgentCanceled, QLatin1String("Agent canceled the password dialog"), request.message); m_calls.removeAt(i); break; } } processNext(); } void SecretAgent::dialogAccepted() { for (int i = 0; i < m_calls.size(); ++i) { SecretsRequest request = m_calls[i]; if (request.type == SecretsRequest::GetSecrets && request.dialog == m_dialog) { NMStringMap tmpOpenconnectSecrets; NMVariantMapMap connection = request.dialog->secrets(); if (connection.contains(QLatin1String("vpn"))) { if (connection.value(QStringLiteral("vpn")).contains(QLatin1String("tmp-secrets"))) { QVariantMap vpnSetting = connection.value(QLatin1String("vpn")); tmpOpenconnectSecrets = qdbus_cast(vpnSetting.take(QLatin1String("tmp-secrets"))); connection.insert(QLatin1String("vpn"), vpnSetting); } } sendSecrets(connection, request.message); NetworkManager::ConnectionSettings::Ptr connectionSettings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(connection)); NetworkManager::ConnectionSettings::Ptr completeConnectionSettings; NetworkManager::Connection::Ptr con = NetworkManager::findConnectionByUuid(connectionSettings->uuid()); if (con) { completeConnectionSettings = con->settings(); } else { completeConnectionSettings = connectionSettings; } if (request.saveSecretsWithoutReply && completeConnectionSettings->connectionType() != NetworkManager::ConnectionSettings::Vpn) { bool requestOffline = true; if (completeConnectionSettings->connectionType() == NetworkManager::ConnectionSettings::Gsm) { NetworkManager::GsmSetting::Ptr gsmSetting = completeConnectionSettings->setting(NetworkManager::Setting::Gsm).staticCast(); if (gsmSetting) { if (gsmSetting->passwordFlags().testFlag(NetworkManager::Setting::NotSaved) || gsmSetting->passwordFlags().testFlag(NetworkManager::Setting::NotRequired)) { requestOffline = false; } else if (gsmSetting->pinFlags().testFlag(NetworkManager::Setting::NotSaved) || gsmSetting->pinFlags().testFlag(NetworkManager::Setting::NotRequired)) { requestOffline = false; } } } else if (completeConnectionSettings->connectionType() == NetworkManager::ConnectionSettings::Wireless) { NetworkManager::WirelessSecuritySetting::Ptr wirelessSecuritySetting = completeConnectionSettings->setting(NetworkManager::Setting::WirelessSecurity).staticCast(); if (wirelessSecuritySetting && wirelessSecuritySetting->keyMgmt() == NetworkManager::WirelessSecuritySetting::WpaEap) { NetworkManager::Security8021xSetting::Ptr security8021xSetting = completeConnectionSettings->setting(NetworkManager::Setting::Security8021x).staticCast(); if (security8021xSetting) { if (security8021xSetting->eapMethods().contains(NetworkManager::Security8021xSetting::EapMethodFast) || security8021xSetting->eapMethods().contains(NetworkManager::Security8021xSetting::EapMethodTtls) || security8021xSetting->eapMethods().contains(NetworkManager::Security8021xSetting::EapMethodPeap)) { if (security8021xSetting->passwordFlags().testFlag(NetworkManager::Setting::NotSaved) || security8021xSetting->passwordFlags().testFlag(NetworkManager::Setting::NotRequired)) { requestOffline = false; } } } } } if (requestOffline) { SecretsRequest requestOffline(SecretsRequest::SaveSecrets); requestOffline.connection = connection; requestOffline.connection_path = request.connection_path; requestOffline.saveSecretsWithoutReply = true; m_calls << requestOffline; } } else if (request.saveSecretsWithoutReply && completeConnectionSettings->connectionType() == NetworkManager::ConnectionSettings::Vpn && !tmpOpenconnectSecrets.isEmpty()) { NetworkManager::VpnSetting::Ptr vpnSetting = completeConnectionSettings->setting(NetworkManager::Setting::Vpn).staticCast(); if (vpnSetting) { NMStringMap data = vpnSetting->data(); NMStringMap secrets = vpnSetting->secrets(); // Load secrets from auth dialog which are returned back to NM if (connection.value(QLatin1String("vpn")).contains(QLatin1String("secrets"))) { secrets.unite(qdbus_cast(connection.value(QLatin1String("vpn")).value(QLatin1String("secrets")))); } // Load temporary secrets from auth dialog which are not returned to NM for (const QString &key : tmpOpenconnectSecrets.keys()) { - if (secrets.contains(QLatin1Literal("save_passwords")) && secrets.value(QLatin1Literal("save_passwords")) == QLatin1String("yes")) { + if (secrets.contains(QLatin1String("save_passwords")) && secrets.value(QLatin1String("save_passwords")) == QLatin1String("yes")) { data.insert(key + QLatin1String("-flags"), QString::number(NetworkManager::Setting::AgentOwned)); } else { data.insert(key + QLatin1String("-flags"), QString::number(NetworkManager::Setting::NotSaved)); } secrets.insert(key, tmpOpenconnectSecrets.value(key)); } vpnSetting->setData(data); vpnSetting->setSecrets(secrets); if (!con) { con = NetworkManager::findConnection(request.connection_path.path()); } if (con) { con->update(completeConnectionSettings->toMap()); } } } m_calls.removeAt(i); break; } } m_dialog->deleteLater(); m_dialog = nullptr; processNext(); } void SecretAgent::dialogRejected() { for (int i = 0; i < m_calls.size(); ++i) { SecretsRequest request = m_calls[i]; if (request.type == SecretsRequest::GetSecrets && request.dialog == m_dialog) { sendError(SecretAgent::UserCanceled, QLatin1String("User canceled the password dialog"), request.message); m_calls.removeAt(i); break; } } m_dialog->deleteLater(); m_dialog = nullptr; processNext(); } void SecretAgent::killDialogs() { int i = 0; while (i < m_calls.size()) { SecretsRequest request = m_calls[i]; if (request.type == SecretsRequest::GetSecrets) { delete request.dialog; m_calls.removeAt(i); } ++i; } } void SecretAgent::walletOpened(bool success) { if (!success) { m_openWalletFailed = true; m_wallet->deleteLater(); m_wallet = nullptr; } else { m_openWalletFailed = false; } processNext(); } void SecretAgent::walletClosed() { if (m_wallet) { m_wallet->deleteLater(); } m_wallet = nullptr; } void SecretAgent::processNext() { int i = 0; while (i < m_calls.size()) { SecretsRequest &request = m_calls[i]; switch (request.type) { case SecretsRequest::GetSecrets: if (processGetSecrets(request)) { m_calls.removeAt(i); continue; } break; case SecretsRequest::SaveSecrets: if (processSaveSecrets(request)) { m_calls.removeAt(i); continue; } break; case SecretsRequest::DeleteSecrets: if (processDeleteSecrets(request)) { m_calls.removeAt(i); continue; } break; } ++i; } } bool SecretAgent::processGetSecrets(SecretsRequest &request) const { if (m_dialog) { return false; } NetworkManager::ConnectionSettings::Ptr connectionSettings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(request.connection)); NetworkManager::Setting::Ptr setting = connectionSettings->setting(request.setting_name); const bool requestNew = request.flags & RequestNew; const bool userRequested = request.flags & UserRequested; const bool allowInteraction = request.flags & AllowInteraction; const bool isVpn = (setting->type() == NetworkManager::Setting::Vpn); const bool isWireGuard = (setting->type() == NetworkManager::Setting::WireGuard); if (isVpn) { NetworkManager::VpnSetting::Ptr vpnSetting = connectionSettings->setting(NetworkManager::Setting::Vpn).dynamicCast(); if (vpnSetting->serviceType() == QLatin1String("org.freedesktop.NetworkManager.ssh") && vpnSetting->data()["auth-type"] == QLatin1String("ssh-agent")) { QString authSock = qgetenv("SSH_AUTH_SOCK"); qCDebug(PLASMA_NM) << Q_FUNC_INFO << "Sending SSH auth socket" << authSock; if (authSock.isEmpty()) { sendError(SecretAgent::NoSecrets, QLatin1String("SSH_AUTH_SOCK not present"), request.message); } else { NMStringMap secrets; secrets.insert(QLatin1String("ssh-auth-sock"), authSock); QVariantMap secretData; secretData.insert(QLatin1String("secrets"), QVariant::fromValue(secrets)); request.connection[request.setting_name] = secretData; sendSecrets(request.connection, request.message); } return true; } } NMStringMap secretsMap; if (!requestNew && useWallet()) { if (m_wallet->isOpen()) { if (m_wallet->hasFolder("Network Management") && m_wallet->setFolder("Network Management")) { QString key = QLatin1Char('{') % connectionSettings->uuid() % QLatin1Char('}') % QLatin1Char(';') % request.setting_name; m_wallet->readMap(key, secretsMap); } } else { qCDebug(PLASMA_NM) << Q_FUNC_INFO << "Waiting for the wallet to open"; return false; } } if (!secretsMap.isEmpty()) { setting->secretsFromStringMap(secretsMap); if (!(isVpn || isWireGuard) && setting->needSecrets(requestNew).isEmpty()) { // Enough secrets were retrieved from storage request.connection[request.setting_name] = setting->secretsToMap(); sendSecrets(request.connection, request.message); return true; } } if (!Configuration::showPasswordDialog()) { sendError(SecretAgent::NoSecrets, "Cannot authenticate", request.message); emit secretsError(request.connection_path.path(), i18n("Authentication to %1 failed. Wrong password?", request.connection.value("connection").value("id").toString())); return true; } else if (isWireGuard && userRequested) { // Just return what we have NMVariantMapMap result; NetworkManager::WireGuardSetting::Ptr wireGuardSetting; wireGuardSetting = connectionSettings->setting(NetworkManager::Setting::WireGuard).dynamicCast(); //FIXME workaround when NM is asking for secrets which should be system-stored, if we send an empty map it // won't ask for additional secrets with AllowInteraction flag which would display the authentication dialog if (wireGuardSetting->secretsToMap().isEmpty()) { // Insert an empty secrets map as it was before I fixed it in NetworkManagerQt to make sure NM will ask again // with flags we need QVariantMap secretsMap; secretsMap.insert(QLatin1String("secrets"), QVariant::fromValue(NMStringMap())); result.insert("wireguard", secretsMap); } else { result.insert("wireguard", wireGuardSetting->secretsToMap()); } sendSecrets(result, request.message); return true; } else if (requestNew || (allowInteraction && !setting->needSecrets(requestNew).isEmpty()) || (allowInteraction && userRequested) || (isVpn && allowInteraction)) { m_dialog = new PasswordDialog(connectionSettings, request.flags, request.setting_name); connect(m_dialog, &PasswordDialog::accepted, this, &SecretAgent::dialogAccepted); connect(m_dialog, &PasswordDialog::rejected, this, &SecretAgent::dialogRejected); if (m_dialog->hasError()) { sendError(m_dialog->error(), m_dialog->errorMessage(), request.message); delete m_dialog; m_dialog = nullptr; return true; } else { request.dialog = m_dialog; request.saveSecretsWithoutReply = !connectionSettings->permissions().isEmpty(); m_dialog->show(); KWindowSystem::setState(m_dialog->winId(), NET::KeepAbove); KWindowSystem::forceActiveWindow(m_dialog->winId()); return false; } } else if (isVpn && userRequested) { // just return what we have NMVariantMapMap result; NetworkManager::VpnSetting::Ptr vpnSetting; vpnSetting = connectionSettings->setting(NetworkManager::Setting::Vpn).dynamicCast(); //FIXME workaround when NM is asking for secrets which should be system-stored, if we send an empty map it // won't ask for additional secrets with AllowInteraction flag which would display the authentication dialog if (vpnSetting->secretsToMap().isEmpty()) { // Insert an empty secrets map as it was before I fixed it in NetworkManagerQt to make sure NM will ask again // with flags we need QVariantMap secretsMap; secretsMap.insert(QLatin1String("secrets"), QVariant::fromValue(NMStringMap())); result.insert("vpn", secretsMap); } else { result.insert("vpn", vpnSetting->secretsToMap()); } sendSecrets(result, request.message); return true; } else if (setting->needSecrets().isEmpty()) { NMVariantMapMap result; result.insert(setting->name(), setting->secretsToMap()); sendSecrets(result, request.message); return true; } else { sendError(SecretAgent::InternalError, QLatin1String("Plasma-nm did not know how to handle the request"), request.message); return true; } } bool SecretAgent::processSaveSecrets(SecretsRequest &request) const { if (useWallet()) { if (m_wallet->isOpen()) { NetworkManager::ConnectionSettings connectionSettings(request.connection); if (!m_wallet->hasFolder("Network Management")) { m_wallet->createFolder("Network Management"); } if (m_wallet->setFolder("Network Management")) { for (const NetworkManager::Setting::Ptr &setting : connectionSettings.settings()) { NMStringMap secretsMap = setting->secretsToStringMap(); if (!secretsMap.isEmpty()) { QString entryName = QLatin1Char('{') % connectionSettings.uuid() % QLatin1Char('}') % QLatin1Char(';') % setting->name(); m_wallet->writeMap(entryName, secretsMap); } } } else if (!request.saveSecretsWithoutReply) { sendError(SecretAgent::InternalError, QLatin1String("Could not store secrets in the wallet."), request.message); return true; } } else { qCDebug(PLASMA_NM) << Q_FUNC_INFO << "Waiting for the wallet to open"; return false; } } if (!request.saveSecretsWithoutReply) { QDBusMessage reply = request.message.createReply(); if (!QDBusConnection::systemBus().send(reply)) { qCWarning(PLASMA_NM) << "Failed put save secrets reply into the queue"; } } return true; } bool SecretAgent::processDeleteSecrets(SecretsRequest &request) const { if (useWallet()) { if (m_wallet->isOpen()) { if (m_wallet->hasFolder("Network Management") && m_wallet->setFolder("Network Management")) { NetworkManager::ConnectionSettings connectionSettings(request.connection); for (const NetworkManager::Setting::Ptr &setting : connectionSettings.settings()) { QString entryName = QLatin1Char('{') % connectionSettings.uuid() % QLatin1Char('}') % QLatin1Char(';') % setting->name(); for (const QString &entry : m_wallet->entryList()) { if (entry.startsWith(entryName)) { m_wallet->removeEntry(entryName); } } } } } else { qCDebug(PLASMA_NM) << Q_FUNC_INFO << "Waiting for the wallet to open"; return false; } } QDBusMessage reply = request.message.createReply(); if (!QDBusConnection::systemBus().send(reply)) { qCWarning(PLASMA_NM) << "Failed put delete secrets reply into the queue"; } return true; } bool SecretAgent::useWallet() const { if (m_wallet) { return true; } /* If opening of KWallet failed before, we should not try to open it again and * we should return false instead */ if (m_openWalletFailed) { m_openWalletFailed = false; return false; } if (KWallet::Wallet::isEnabled()) { m_wallet = KWallet::Wallet::openWallet(KWallet::Wallet::LocalWallet(), 0, KWallet::Wallet::Asynchronous); if (m_wallet) { connect(m_wallet, &KWallet::Wallet::walletOpened, this, &SecretAgent::walletOpened); connect(m_wallet, &KWallet::Wallet::walletClosed, this, &SecretAgent::walletClosed); return true; } else { qCWarning(PLASMA_NM) << "Error opening kwallet."; } } else if (m_wallet) { m_wallet->deleteLater(); m_wallet = nullptr; } return false; } bool SecretAgent::hasSecrets(const NMVariantMapMap &connection) const { NetworkManager::ConnectionSettings connectionSettings(connection); for (const NetworkManager::Setting::Ptr &setting : connectionSettings.settings()) { if (!setting->secretsToMap().isEmpty()) { return true; } } return false; } void SecretAgent::sendSecrets(const NMVariantMapMap &secrets, const QDBusMessage &message) const { QDBusMessage reply; reply = message.createReply(QVariant::fromValue(secrets)); if (!QDBusConnection::systemBus().send(reply)) { qCWarning(PLASMA_NM) << "Failed put the secret into the queue"; } } void SecretAgent::importSecretsFromPlainTextFiles() { KConfig config(QLatin1String("plasma-networkmanagement"), KConfig::SimpleConfig); // No action is required when the list of secrets is empty if (!config.groupList().isEmpty()) { for (const QString &groupName : config.groupList()) { QString loadedUuid = groupName.split(';').first().remove('{').remove('}'); QString loadedSettingType = groupName.split(';').last(); NetworkManager::Connection::Ptr connection = NetworkManager::findConnectionByUuid(loadedUuid); if (connection) { NetworkManager::Setting::SecretFlags secretFlags = KWallet::Wallet::isEnabled() ? NetworkManager::Setting::AgentOwned : NetworkManager::Setting::None; QMap secrets = config.entryMap(groupName); NMVariantMapMap settings = connection->settings()->toMap(); for (const QString &setting : settings.keys()) { if (setting == QLatin1String("vpn")) { NetworkManager::VpnSetting::Ptr vpnSetting = connection->settings()->setting(NetworkManager::Setting::Vpn).staticCast(); if (vpnSetting) { // Add loaded secrets from the config file vpnSetting->secretsFromStringMap(secrets); NMStringMap vpnData = vpnSetting->data(); // Reset flags, we can't save secrets to our secret agent when KWallet is not enabled, because // we dropped support for plaintext files, therefore they need to be stored to NetworkManager for (const QString &key : vpnData.keys()) { if (key.endsWith(QLatin1String("-flags"))) { vpnData.insert(key, QString::number((int)secretFlags)); } } vpnSetting->setData(vpnData); settings.insert(setting, vpnSetting->toMap()); connection->update(settings); } } else { if (setting == loadedSettingType) { QVariantMap tmpSetting = settings.value(setting); // Reset flags, we can't save secrets to our secret agent when KWallet is not enabled, because // we dropped support for plaintext files, therefore they need to be stored to NetworkManager for (const QString &key : tmpSetting.keys()) { if (key.endsWith(QLatin1String("-flags"))) { tmpSetting.insert(key, (int)secretFlags); } } // Add loaded secrets from the config file QMap::const_iterator it = secrets.constBegin(); QMap::const_iterator end = secrets.constEnd(); for (; it != end; ++it) { tmpSetting.insert(it.key(), it.value()); } // Replace the old setting with the new one settings.insert(setting, tmpSetting); // Update the connection which re-saves secrets connection->update(settings); } } } } // Remove the group KConfigGroup group(&config, groupName); group.deleteGroup(); } } } diff --git a/libs/handler.cpp b/libs/handler.cpp index 0c93eeba..5edf988f 100644 --- a/libs/handler.cpp +++ b/libs/handler.cpp @@ -1,636 +1,636 @@ /* Copyright 2013-2014 Jan Grulich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "handler.h" #include "connectioneditordialog.h" #include "uiutils.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if WITH_MODEMMANAGER_SUPPORT #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #define AGENT_SERVICE "org.kde.kded5" #define AGENT_PATH "/modules/networkmanagement" #define AGENT_IFACE "org.kde.plasmanetworkmanagement" Handler::Handler(QObject *parent) : QObject(parent) , m_tmpWirelessEnabled(NetworkManager::isWirelessEnabled()) , m_tmpWwanEnabled(NetworkManager::isWwanEnabled()) { initKdedModule(); QDBusConnection::sessionBus().connect(QStringLiteral(AGENT_SERVICE), QStringLiteral(AGENT_PATH), QStringLiteral(AGENT_IFACE), QStringLiteral("registered"), this, SLOT(initKdedModule())); QDBusConnection::sessionBus().connect(QStringLiteral(AGENT_SERVICE), QStringLiteral(AGENT_PATH), QStringLiteral(AGENT_IFACE), QStringLiteral("secretsError"), this, SLOT(secretAgentError(QString, QString))); // Interval (in ms) between attempts to scan for wifi networks m_wirelessScanRetryTimer.setInterval(2000); m_wirelessScanRetryTimer.setSingleShot(true); } Handler::~Handler() { } void Handler::activateConnection(const QString& connection, const QString& device, const QString& specificObject) { NetworkManager::Connection::Ptr con = NetworkManager::findConnection(connection); if (!con) { qCWarning(PLASMA_NM) << "Not possible to activate this connection"; return; } if (con->settings()->connectionType() == NetworkManager::ConnectionSettings::Vpn) { NetworkManager::VpnSetting::Ptr vpnSetting = con->settings()->setting(NetworkManager::Setting::Vpn).staticCast(); if (vpnSetting) { qCDebug(PLASMA_NM) << "Checking VPN" << con->name() << "type:" << vpnSetting->serviceType(); bool pluginMissing = false; // Check missing plasma-nm VPN plugin const KService::List services = KServiceTypeTrader::self()->query("PlasmaNetworkManagement/VpnUiPlugin", QString::fromLatin1("[X-NetworkManager-Services]=='%1'").arg(vpnSetting->serviceType())); pluginMissing = services.isEmpty(); // Check missing NetworkManager VPN plugin if (!pluginMissing) { GSList *plugins = nullptr; plugins = nm_vpn_plugin_info_list_load(); NMVpnPluginInfo *plugin_info = nm_vpn_plugin_info_list_find_by_service(plugins, vpnSetting->serviceType().toStdString().c_str()); pluginMissing = !plugin_info; } if (pluginMissing) { qCWarning(PLASMA_NM) << "VPN" << vpnSetting->serviceType() << "not found, skipping"; KNotification *notification = new KNotification("MissingVpnPlugin", KNotification::CloseOnTimeout, this); notification->setComponentName("networkmanagement"); notification->setTitle(con->name()); notification->setText(i18n("Missing VPN plugin")); notification->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(KIconLoader::SizeHuge)); notification->sendEvent(); return; } } } #if WITH_MODEMMANAGER_SUPPORT if (con->settings()->connectionType() == NetworkManager::ConnectionSettings::Gsm) { NetworkManager::ModemDevice::Ptr nmModemDevice = NetworkManager::findNetworkInterface(device).objectCast(); if (nmModemDevice) { ModemManager::ModemDevice::Ptr mmModemDevice = ModemManager::findModemDevice(nmModemDevice->udi()); if (mmModemDevice) { ModemManager::Modem::Ptr modem = mmModemDevice->interface(ModemManager::ModemDevice::ModemInterface).objectCast(); NetworkManager::GsmSetting::Ptr gsmSetting = con->settings()->setting(NetworkManager::Setting::Gsm).staticCast(); if (gsmSetting && gsmSetting->pinFlags() == NetworkManager::Setting::NotSaved && modem && modem->unlockRequired() > MM_MODEM_LOCK_NONE) { QDBusInterface managerIface("org.kde.plasmanetworkmanagement", "/org/kde/plasmanetworkmanagement", "org.kde.plasmanetworkmanagement", QDBusConnection::sessionBus(), this); managerIface.call("unlockModem", mmModemDevice->uni()); connect(modem.data(), &ModemManager::Modem::unlockRequiredChanged, this, &Handler::unlockRequiredChanged); m_tmpConnectionPath = connection; m_tmpDevicePath = device; m_tmpSpecificPath = specificObject; return; } } } } #endif QDBusPendingReply reply = NetworkManager::activateConnection(connection, device, specificObject); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); watcher->setProperty("action", Handler::ActivateConnection); watcher->setProperty("connection", con->name()); connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); } QString Handler::wifiCode(const QString& connectionPath, const QString& ssid, int _securityType) const { NetworkManager::WirelessSecurityType securityType = static_cast(_securityType); QString ret = QStringLiteral("WIFI:S:") + ssid + QLatin1Char(';'); if (securityType != NetworkManager::NoneSecurity) { switch (securityType) { case NetworkManager::NoneSecurity: break; case NetworkManager::StaticWep: ret += "T:WEP;"; break; case NetworkManager::WpaPsk: case NetworkManager::Wpa2Psk: ret += "T:WPA;"; break; default: case NetworkManager::DynamicWep: case NetworkManager::WpaEap: case NetworkManager::Wpa2Eap: case NetworkManager::Leap: return {}; } } NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(connectionPath); if(!connection) return {}; const auto key = QStringLiteral("802-11-wireless-security"); auto reply = connection->secrets(key); const auto secret = reply.argumentAt<0>()[key]; QString pass; switch (securityType) { case NetworkManager::NoneSecurity: break; case NetworkManager::WpaPsk: case NetworkManager::Wpa2Psk: pass = secret["psk"].toString(); break; default: return {}; } if (!pass.isEmpty()) ret += QStringLiteral("P:") + pass + QLatin1Char(';'); return ret + QLatin1Char(';'); } void Handler::addAndActivateConnection(const QString& device, const QString& specificObject, const QString& password) { NetworkManager::AccessPoint::Ptr ap; NetworkManager::WirelessDevice::Ptr wifiDev; for (const NetworkManager::Device::Ptr &dev : NetworkManager::networkInterfaces()) { if (dev->type() == NetworkManager::Device::Wifi) { wifiDev = dev.objectCast(); ap = wifiDev->findAccessPoint(specificObject); if (ap) { break; } } } if (!ap) { return; } NetworkManager::ConnectionSettings::Ptr settings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(NetworkManager::ConnectionSettings::Wireless)); settings->setId(ap->ssid()); settings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); settings->setAutoconnect(true); settings->addToPermissions(KUser().loginName(), QString()); NetworkManager::WirelessSetting::Ptr wifiSetting = settings->setting(NetworkManager::Setting::Wireless).dynamicCast(); wifiSetting->setInitialized(true); wifiSetting = settings->setting(NetworkManager::Setting::Wireless).dynamicCast(); wifiSetting->setSsid(ap->ssid().toUtf8()); if (ap->mode() == NetworkManager::AccessPoint::Adhoc) { wifiSetting->setMode(NetworkManager::WirelessSetting::Adhoc); } NetworkManager::WirelessSecuritySetting::Ptr wifiSecurity = settings->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); NetworkManager::WirelessSecurityType securityType = NetworkManager::findBestWirelessSecurity(wifiDev->wirelessCapabilities(), true, (ap->mode() == NetworkManager::AccessPoint::Adhoc), ap->capabilities(), ap->wpaFlags(), ap->rsnFlags()); if (securityType != NetworkManager::NoneSecurity) { wifiSecurity->setInitialized(true); wifiSetting->setSecurity("802-11-wireless-security"); } if (securityType == NetworkManager::Leap || securityType == NetworkManager::DynamicWep || securityType == NetworkManager::Wpa2Eap || securityType == NetworkManager::WpaEap) { if (securityType == NetworkManager::DynamicWep || securityType == NetworkManager::Leap) { wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::Ieee8021x); if (securityType == NetworkManager::Leap) { wifiSecurity->setAuthAlg(NetworkManager::WirelessSecuritySetting::Leap); } } else { wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaEap); } m_tmpConnectionUuid = settings->uuid(); m_tmpDevicePath = device; m_tmpSpecificPath = specificObject; QPointer editor = new ConnectionEditorDialog(settings); editor->show(); KWindowSystem::setState(editor->winId(), NET::KeepAbove); KWindowSystem::forceActiveWindow(editor->winId()); connect(editor.data(), &ConnectionEditorDialog::accepted, [editor, this] () { addConnection(editor->setting()); }); connect(editor.data(), &ConnectionEditorDialog::finished, [editor] () { if (editor) { editor->deleteLater(); } }); editor->setModal(true); editor->show(); } else { if (securityType == NetworkManager::StaticWep) { wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::Wep); wifiSecurity->setWepKey0(password); if (KWallet::Wallet::isEnabled()) { wifiSecurity->setWepKeyFlags(NetworkManager::Setting::AgentOwned); } } else { if (ap->mode() == NetworkManager::AccessPoint::Adhoc) { wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaNone); } else { wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk); } wifiSecurity->setPsk(password); if (KWallet::Wallet::isEnabled()) { wifiSecurity->setPskFlags(NetworkManager::Setting::AgentOwned); } } QDBusPendingReply reply = NetworkManager::addAndActivateConnection(settings->toMap(), device, specificObject); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); watcher->setProperty("action", Handler::AddAndActivateConnection); watcher->setProperty("connection", settings->name()); connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); } settings.clear(); } void Handler::addConnection(const NMVariantMapMap& map) { QDBusPendingReply reply = NetworkManager::addConnection(map); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); watcher->setProperty("action", AddConnection); watcher->setProperty("connection", map.value("connection").value("id")); connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); } void Handler::deactivateConnection(const QString& connection, const QString& device) { NetworkManager::Connection::Ptr con = NetworkManager::findConnection(connection); if (!con) { qCWarning(PLASMA_NM) << "Not possible to deactivate this connection"; return; } QDBusPendingReply<> reply; for (const NetworkManager::ActiveConnection::Ptr &active : NetworkManager::activeConnections()) { if (active->uuid() == con->uuid() && ((!active->devices().isEmpty() && active->devices().first() == device) || active->vpn())) { if (active->vpn()) { reply = NetworkManager::deactivateConnection(active->path()); } else { NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(active->devices().first()); if (device) { reply = device->disconnectInterface(); } } } } QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); watcher->setProperty("action", Handler::DeactivateConnection); connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); } void Handler::disconnectAll() { for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { device->disconnectInterface(); } } void Handler::enableAirplaneMode(bool enable) { if (enable) { m_tmpWirelessEnabled = NetworkManager::isWirelessEnabled(); m_tmpWwanEnabled = NetworkManager::isWwanEnabled(); enableBluetooth(false); enableWireless(false); enableWwan(false); } else { enableBluetooth(true); if (m_tmpWirelessEnabled) { enableWireless(true); } if (m_tmpWwanEnabled) { enableWwan(true); } } } void Handler::enableBluetooth(bool enable) { qDBusRegisterMetaType< QMap >(); QDBusMessage message = QDBusMessage::createMethodCall("org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); QDBusPendingReply > reply = QDBusConnection::systemBus().asyncCall(message); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); connect(watcher, &QDBusPendingCallWatcher::finished, [this, enable] (QDBusPendingCallWatcher *watcher) { QDBusPendingReply > reply = *watcher; if (reply.isValid()) { for (const QDBusObjectPath &path : reply.value().keys()) { const QString objPath = path.path(); qCDebug(PLASMA_NM) << "inspecting path" << objPath; const QStringList interfaces = reply.value().value(path).keys(); qCDebug(PLASMA_NM) << "interfaces:" << interfaces; if (interfaces.contains("org.bluez.Adapter1")) { // We need to check previous state first if (!enable) { QDBusMessage message = QDBusMessage::createMethodCall("org.bluez", objPath, "org.freedesktop.DBus.Properties", "Get"); QList arguments; - arguments << QLatin1Literal("org.bluez.Adapter1"); - arguments << QLatin1Literal("Powered"); + arguments << QLatin1String("org.bluez.Adapter1"); + arguments << QLatin1String("Powered"); message.setArguments(arguments); QDBusPendingReply getReply = QDBusConnection::systemBus().asyncCall(message); QDBusPendingCallWatcher *getWatcher = new QDBusPendingCallWatcher(getReply, this); connect(getWatcher, &QDBusPendingCallWatcher::finished, [this, objPath] (QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isValid()) { m_bluetoothAdapters.insert(objPath, reply.value().toBool()); QDBusMessage message = QDBusMessage::createMethodCall("org.bluez", objPath, "org.freedesktop.DBus.Properties", "Set"); QList arguments; - arguments << QLatin1Literal("org.bluez.Adapter1"); - arguments << QLatin1Literal("Powered"); + arguments << QLatin1String("org.bluez.Adapter1"); + arguments << QLatin1String("Powered"); arguments << QVariant::fromValue(QDBusVariant(QVariant(false))); message.setArguments(arguments); QDBusConnection::systemBus().asyncCall(message); } watcher->deleteLater(); }); } else if (enable && m_bluetoothAdapters.value(objPath)) { QDBusMessage message = QDBusMessage::createMethodCall("org.bluez", objPath, "org.freedesktop.DBus.Properties", "Set"); QList arguments; - arguments << QLatin1Literal("org.bluez.Adapter1"); - arguments << QLatin1Literal("Powered"); + arguments << QLatin1String("org.bluez.Adapter1"); + arguments << QLatin1String("Powered"); arguments << QVariant::fromValue(QDBusVariant(QVariant(enable))); message.setArguments(arguments); QDBusConnection::systemBus().asyncCall(message); } } } } watcher->deleteLater(); }); } void Handler::enableNetworking(bool enable) { NetworkManager::setNetworkingEnabled(enable); } void Handler::enableWireless(bool enable) { NetworkManager::setWirelessEnabled(enable); } void Handler::enableWwan(bool enable) { NetworkManager::setWwanEnabled(enable); } void Handler::removeConnection(const QString& connection) { NetworkManager::Connection::Ptr con = NetworkManager::findConnection(connection); if (!con || con->uuid().isEmpty()) { qCWarning(PLASMA_NM) << "Not possible to remove connection " << connection; return; } // Remove slave connections for (const NetworkManager::Connection::Ptr &connection : NetworkManager::listConnections()) { NetworkManager::ConnectionSettings::Ptr settings = connection->settings(); if (settings->master() == con->uuid()) { connection->remove(); } } QDBusPendingReply<> reply = con->remove(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); watcher->setProperty("action", Handler::RemoveConnection); watcher->setProperty("connection", con->name()); connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); } void Handler::updateConnection(const NetworkManager::Connection::Ptr& connection, const NMVariantMapMap& map) { QDBusPendingReply<> reply = connection->update(map); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); watcher->setProperty("action", UpdateConnection); watcher->setProperty("connection", connection->name()); connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); } void Handler::requestScan(const QString &interface) { for (NetworkManager::Device::Ptr device : NetworkManager::networkInterfaces()) { if (device->type() == NetworkManager::Device::Wifi) { NetworkManager::WirelessDevice::Ptr wifiDevice = device.objectCast(); if (wifiDevice && wifiDevice->state() != NetworkManager::WirelessDevice::Unavailable) { if (!interface.isEmpty() && interface != wifiDevice->interfaceName()) { continue; } qCDebug(PLASMA_NM) << "Requesting wifi scan on device" << wifiDevice->interfaceName(); QDBusPendingReply<> reply = wifiDevice->requestScan(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); watcher->setProperty("action", Handler::RequestScan); watcher->setProperty("interface", wifiDevice->interfaceName()); connect(watcher, &QDBusPendingCallWatcher::finished, this, &Handler::replyFinished); } } } } void Handler::scanRequestFailed(const QString &interface) { if (m_wirelessScanRetryTimer.isActive()) { return; } qCDebug(PLASMA_NM) << "Trying soon a new scan on" << interface; emit wirelessScanTimerEnabled(false); auto retryAction = [this,interface]() { m_wirelessScanRetryTimer.disconnect(); requestScan(interface); }; connect(&m_wirelessScanRetryTimer, &QTimer::timeout, this, retryAction); m_wirelessScanRetryTimer.start(); } void Handler::initKdedModule() { QDBusMessage initMsg = QDBusMessage::createMethodCall(QStringLiteral(AGENT_SERVICE), QStringLiteral(AGENT_PATH), QStringLiteral(AGENT_IFACE), QStringLiteral("init")); QDBusConnection::sessionBus().send(initMsg); } void Handler::secretAgentError(const QString &connectionPath, const QString &message) { // If the password was wrong, forget it removeConnection(connectionPath); emit connectionActivationFailed(connectionPath, message); } void Handler::replyFinished(QDBusPendingCallWatcher * watcher) { QDBusPendingReply<> reply = *watcher; if (reply.isError() || !reply.isValid()) { KNotification *notification = nullptr; QString error = reply.error().message(); Handler::HandlerAction action = (Handler::HandlerAction)watcher->property("action").toUInt(); switch (action) { case Handler::ActivateConnection: notification = new KNotification("FailedToActivateConnection", KNotification::CloseOnTimeout, this); notification->setTitle(i18n("Failed to activate %1", watcher->property("connection").toString())); break; case Handler::AddAndActivateConnection: notification = new KNotification("FailedToAddConnection", KNotification::CloseOnTimeout, this); notification->setTitle(i18n("Failed to add %1", watcher->property("connection").toString())); break; case Handler::AddConnection: notification = new KNotification("FailedToAddConnection", KNotification::CloseOnTimeout, this); notification->setTitle(i18n("Failed to add connection %1", watcher->property("connection").toString())); break; case Handler::DeactivateConnection: notification = new KNotification("FailedToDeactivateConnection", KNotification::CloseOnTimeout, this); notification->setTitle(i18n("Failed to deactivate %1", watcher->property("connection").toString())); break; case Handler::RemoveConnection: notification = new KNotification("FailedToRemoveConnection", KNotification::CloseOnTimeout, this); notification->setTitle(i18n("Failed to remove %1", watcher->property("connection").toString())); break; case Handler::UpdateConnection: notification = new KNotification("FailedToUpdateConnection", KNotification::CloseOnTimeout, this); notification->setTitle(i18n("Failed to update connection %1", watcher->property("connection").toString())); break; case Handler::RequestScan: { const QString interface = watcher->property("interface").toString(); qCWarning(PLASMA_NM) << "Wireless scan on" << interface << "failed:" << error; scanRequestFailed(interface); break; } default: break; } if (notification) { notification->setComponentName("networkmanagement"); notification->setText(error); notification->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(KIconLoader::SizeHuge)); notification->sendEvent(); } } else { KNotification *notification = nullptr; Handler::HandlerAction action = (Handler::HandlerAction)watcher->property("action").toUInt(); switch (action) { case Handler::AddConnection: notification = new KNotification("ConnectionAdded", KNotification::CloseOnTimeout, this); notification->setText(i18n("Connection %1 has been added", watcher->property("connection").toString())); break; case Handler::RemoveConnection: notification = new KNotification("ConnectionRemoved", KNotification::CloseOnTimeout, this); notification->setText(i18n("Connection %1 has been removed", watcher->property("connection").toString())); break; case Handler::UpdateConnection: notification = new KNotification("ConnectionUpdated", KNotification::CloseOnTimeout, this); notification->setText(i18n("Connection %1 has been updated", watcher->property("connection").toString())); break; case Handler::RequestScan: qCDebug(PLASMA_NM) << "Wireless scan on" << watcher->property("interface").toString() << "succeeded"; emit wirelessScanTimerEnabled(true); break; default: break; } if (notification) { notification->setComponentName("networkmanagement"); notification->setTitle(watcher->property("connection").toString()); notification->setPixmap(QIcon::fromTheme("dialog-information").pixmap(KIconLoader::SizeHuge)); notification->sendEvent(); } } watcher->deleteLater(); } #if WITH_MODEMMANAGER_SUPPORT void Handler::unlockRequiredChanged(MMModemLock modemLock) { if (modemLock == MM_MODEM_LOCK_NONE) { activateConnection(m_tmpConnectionPath, m_tmpDevicePath, m_tmpSpecificPath); } } #endif