diff --git a/krfb/invitationsrfbserver.cpp b/krfb/invitationsrfbserver.cpp index cee6224..04bcd59 100644 --- a/krfb/invitationsrfbserver.cpp +++ b/krfb/invitationsrfbserver.cpp @@ -1,225 +1,236 @@ /* Copyright (C) 2009-2010 Collabora Ltd @author George Goldberg @author George Kiagiadakis Copyright (C) 2007 Alessandro Praduroux Copyright (C) 2001-2003 by Tim Jansen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "invitationsrfbserver.h" #include "invitationsrfbclient.h" #include "krfbconfig.h" #include "rfbservermanager.h" #include #include #include #include #include #include #include #include #include #include using KWallet::Wallet; //static InvitationsRfbServer *InvitationsRfbServer::instance; //static void InvitationsRfbServer::init() { instance = new InvitationsRfbServer; instance->m_publicService = new KDNSSD::PublicService( i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()), "_rfb._tcp", KrfbConfig::port()); instance->setListeningAddress("0.0.0.0"); instance->setListeningPort(KrfbConfig::port()); instance->setPasswordRequired(true); + instance->m_wallet = nullptr; if (KrfbConfig::noWallet()) { - instance->walletOpened(false); - } - else { - instance->m_wallet = Wallet::openWallet( - Wallet::NetworkWallet(), 0, Wallet::Asynchronous); - if(instance->m_wallet) { - connect(instance->m_wallet, &KWallet::Wallet::walletOpened, - instance, &InvitationsRfbServer::walletOpened); - } + instance->walletOpened(false); + } else { + instance->openKWallet(); } } const QString& InvitationsRfbServer::desktopPassword() const { return m_desktopPassword; } void InvitationsRfbServer::setDesktopPassword(const QString& password) { m_desktopPassword = password; } const QString& InvitationsRfbServer::unattendedPassword() const { return m_unattendedPassword; } void InvitationsRfbServer::setUnattendedPassword(const QString& password) { m_unattendedPassword = password; } bool InvitationsRfbServer::allowUnattendedAccess() const { return m_allowUnattendedAccess; } bool InvitationsRfbServer::start() { if(RfbServer::start()) { if(KrfbConfig::publishService()) m_publicService->publishAsync(); return true; } return false; } void InvitationsRfbServer::stop() { if(m_publicService->isPublished()) m_publicService->stop(); RfbServer::stop(); } void InvitationsRfbServer::toggleUnattendedAccess(bool allow) { m_allowUnattendedAccess = allow; } InvitationsRfbServer::InvitationsRfbServer() { m_desktopPassword = readableRandomString(4)+'-'+readableRandomString(3); m_unattendedPassword = readableRandomString(4)+'-'+readableRandomString(3); KConfigGroup krfbConfig(KSharedConfig::openConfig(),"Security"); m_allowUnattendedAccess = krfbConfig.readEntry( "allowUnattendedAccess", QVariant(false)).toBool(); } InvitationsRfbServer::~InvitationsRfbServer() { stop(); - KConfigGroup krfbConfig(KSharedConfig::openConfig(),"Security"); - krfbConfig.writeEntry("allowUnattendedAccess",m_allowUnattendedAccess); - if(!KrfbConfig::noWallet()) { - if (m_wallet && m_wallet->isOpen()) { - if( (m_wallet->currentFolder()=="krfb") || - ((m_wallet->hasFolder("krfb") || m_wallet->createFolder("krfb")) && - m_wallet->setFolder("krfb")) ) { - - m_wallet->writePassword("desktopSharingPassword",m_desktopPassword); - m_wallet->writePassword("unattendedAccessPassword",m_unattendedPassword); - } - } + KConfigGroup krfbConfig(KSharedConfig::openConfig(), "Security"); + krfbConfig.writeEntry("allowUnattendedAccess", m_allowUnattendedAccess); + + if (!KrfbConfig::noWallet() && m_wallet) { + closeKWallet(); } else { krfbConfig.writeEntry("desktopPassword", KStringHandler::obscure(m_desktopPassword)); krfbConfig.writeEntry("unattendedPassword", KStringHandler::obscure(m_unattendedPassword)); krfbConfig.writeEntry("allowUnattendedAccess", m_allowUnattendedAccess); } } PendingRfbClient* InvitationsRfbServer::newClient(rfbClientPtr client) { return new PendingInvitationsRfbClient(client, this); } +void InvitationsRfbServer::openKWallet() +{ + m_wallet = Wallet::openWallet(Wallet::NetworkWallet(), 0, Wallet::Asynchronous); + if (m_wallet) { + connect(instance->m_wallet, &KWallet::Wallet::walletOpened, + this, &InvitationsRfbServer::walletOpened); + } +} + +void InvitationsRfbServer::closeKWallet() +{ + if (m_wallet && m_wallet->isOpen()) { + if ((m_wallet->currentFolder() == "krfb") || + ((m_wallet->hasFolder("krfb") || m_wallet->createFolder("krfb")) && + m_wallet->setFolder("krfb")) ) { + m_wallet->writePassword("desktopSharingPassword", m_desktopPassword); + m_wallet->writePassword("unattendedAccessPassword", m_unattendedPassword); + } + delete m_wallet; // closes the wallet + m_wallet = nullptr; + } +} + void InvitationsRfbServer::walletOpened(bool opened) { QString desktopPassword; QString unattendedPassword; Q_ASSERT(m_wallet); if( opened && ( m_wallet->hasFolder("krfb") || m_wallet->createFolder("krfb") ) && m_wallet->setFolder("krfb") ) { if(m_wallet->readPassword("desktopSharingPassword", desktopPassword)==0 && !desktopPassword.isEmpty()) { m_desktopPassword = desktopPassword; emit passwordChanged(m_desktopPassword); } if(m_wallet->readPassword("unattendedAccessPassword", unattendedPassword)==0 && !unattendedPassword.isEmpty()) { m_unattendedPassword = unattendedPassword; } } else { qDebug() << "Could not open KWallet, Falling back to config file"; KConfigGroup krfbConfig(KSharedConfig::openConfig(),"Security"); desktopPassword = KStringHandler::obscure(krfbConfig.readEntry( "desktopPassword", QString())); if(!desktopPassword.isEmpty()) { m_desktopPassword = desktopPassword; emit passwordChanged(m_desktopPassword); } unattendedPassword = KStringHandler::obscure(krfbConfig.readEntry( "unattendedPassword", QString())); if(!unattendedPassword.isEmpty()) { m_unattendedPassword = unattendedPassword; } } } // a random string that doesn't contain i, I, o, O, 1, l, 0 // based on KRandom::randomString() QString InvitationsRfbServer::readableRandomString(int length) { QString str; while (length) { int r = KRandom::random() % 62; r += 48; if (r > 57) { r += 7; } if (r > 90) { r += 6; } char c = char(r); if ((c == 'i') || (c == 'I') || (c == '1') || (c == 'l') || (c == 'o') || (c == 'O') || (c == '0')) { continue; } str += c; length--; } return str; } diff --git a/krfb/invitationsrfbserver.h b/krfb/invitationsrfbserver.h index f3f6277..6b6b16d 100644 --- a/krfb/invitationsrfbserver.h +++ b/krfb/invitationsrfbserver.h @@ -1,73 +1,75 @@ /* Copyright (C) 2009-2010 Collabora Ltd @author George Goldberg @author George Kiagiadakis Copyright (C) 2007 Alessandro Praduroux This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef INVITATIONSRFBSERVER_H #define INVITATIONSRFBSERVER_H #include "rfbserver.h" namespace KWallet { class Wallet; } namespace KDNSSD { class PublicService; } class InvitationsRfbServer : public RfbServer { Q_OBJECT public: static InvitationsRfbServer *instance; static void init(); const QString& desktopPassword() const; void setDesktopPassword(const QString&); const QString& unattendedPassword() const; void setUnattendedPassword(const QString&); bool allowUnattendedAccess() const; Q_SIGNALS: void passwordChanged(const QString&); public Q_SLOTS: bool start() override; void stop() override; void toggleUnattendedAccess(bool allow); + void openKWallet(); + void closeKWallet(); protected: InvitationsRfbServer(); ~InvitationsRfbServer() override; PendingRfbClient* newClient(rfbClientPtr client) override; private Q_SLOTS: void walletOpened(bool); private: KDNSSD::PublicService *m_publicService; bool m_allowUnattendedAccess; QString m_desktopPassword; QString m_unattendedPassword; KWallet::Wallet *m_wallet; QString readableRandomString(int); Q_DISABLE_COPY(InvitationsRfbServer) }; #endif // INVITATIONSRFBSERVER_H diff --git a/krfb/mainwindow.cpp b/krfb/mainwindow.cpp index 9c64fce..2df4e14 100644 --- a/krfb/mainwindow.cpp +++ b/krfb/mainwindow.cpp @@ -1,264 +1,293 @@ /* This file is part of the KDE project Copyright (C) 2007 Alessandro Praduroux Copyright (C) 2013 Amandeep Singh This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #include "mainwindow.h" #include "invitationsrfbserver.h" #include "krfbconfig.h" #include "ui_configtcp.h" #include "ui_configsecurity.h" #include "ui_configframebuffer.h" #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class TCP: public QWidget, public Ui::TCP { public: TCP(QWidget *parent = nullptr) : QWidget(parent) { setupUi(this); } }; class Security: public QWidget, public Ui::Security { public: Security(QWidget *parent = nullptr) : QWidget(parent) { setupUi(this); + walletWarning = new KMessageWidget(this); + walletWarning->setText(i18n("Storing passwords in config file is insecure!")); + walletWarning->setCloseButtonVisible(false); + walletWarning->setMessageType(KMessageWidget::Warning); + walletWarning->hide(); + vboxLayout->addWidget(walletWarning); + + // show warning when "noWallet" checkbox is unchecked + QObject::connect(kcfg_noWallet, &QCheckBox::toggled, [this](bool checked){ + walletWarning->setVisible(!checked); + }); } + + KMessageWidget *walletWarning = nullptr; }; class ConfigFramebuffer: public QWidget, public Ui::Framebuffer { public: ConfigFramebuffer(QWidget *parent = nullptr) : QWidget(parent) { setupUi(this); // hide the line edit with framebuffer string kcfg_preferredFrameBufferPlugin->hide(); // fill drop-down combo with a list of real existing plugins this->fillFrameBuffersCombo(); // initialize combo with currently configured framebuffer plugin cb_preferredFrameBufferPlugin->setCurrentText(KrfbConfig::preferredFrameBufferPlugin()); // connect signals between combo<->lineedit // if we change selection in combo, lineedit is updated QObject::connect(cb_preferredFrameBufferPlugin, &QComboBox::currentTextChanged, kcfg_preferredFrameBufferPlugin, &QLineEdit::setText); } void fillFrameBuffersCombo() { const QVector plugins = KPluginLoader::findPlugins( QStringLiteral("krfb"), [](const KPluginMetaData & md) { return md.serviceTypes().contains(QStringLiteral("krfb/framebuffer")); }); QSet unique; QVectorIterator i(plugins); i.toBack(); while (i.hasPrevious()) { const KPluginMetaData &metadata = i.previous(); if (unique.contains(metadata.pluginId())) continue; cb_preferredFrameBufferPlugin->addItem(metadata.pluginId()); unique.insert(metadata.pluginId()); } } }; MainWindow::MainWindow(QWidget *parent) : KXmlGuiWindow(parent) { setAttribute(Qt::WA_DeleteOnClose, false); m_passwordEditable = false; m_passwordLineEdit = new KLineEdit(this); m_passwordLineEdit->setVisible(false); m_passwordLineEdit->setAlignment(Qt::AlignHCenter); QWidget *mainWidget = new QWidget; m_ui.setupUi(mainWidget); m_ui.krfbIconLabel->setPixmap(QIcon::fromTheme("krfb").pixmap(128)); m_ui.enableUnattendedCheckBox->setChecked( InvitationsRfbServer::instance->allowUnattendedAccess()); setCentralWidget(mainWidget); connect(m_ui.passwordEditButton, &QToolButton::clicked, this, &MainWindow::editPassword); connect(m_ui.enableSharingCheckBox, &QCheckBox::toggled, this, &MainWindow::toggleDesktopSharing); connect(m_ui.enableUnattendedCheckBox, &QCheckBox::toggled, InvitationsRfbServer::instance, &InvitationsRfbServer::toggleUnattendedAccess); connect(m_ui.unattendedPasswordButton, &QPushButton::clicked, this, &MainWindow::editUnattendedPassword); connect(m_ui.addressAboutButton, &QToolButton::clicked, this, &MainWindow::aboutConnectionAddress); connect(m_ui.unattendedAboutButton, &QToolButton::clicked, this, &MainWindow::aboutUnattendedMode); connect(InvitationsRfbServer::instance, &InvitationsRfbServer::passwordChanged, this, &MainWindow::passwordChanged); // Figure out the address int port = KrfbConfig::port(); QList interfaceList = QNetworkInterface::allInterfaces(); foreach(const QNetworkInterface & interface, interfaceList) { if(interface.flags() & QNetworkInterface::IsLoopBack) continue; if(interface.flags() & QNetworkInterface::IsRunning && !interface.addressEntries().isEmpty()) m_ui.addressDisplayLabel->setText(QString("%1 : %2") .arg(interface.addressEntries().first().ip().toString()) .arg(port)); } //Figure out the password m_ui.passwordDisplayLabel->setText( InvitationsRfbServer::instance->desktopPassword()); KStandardAction::quit(QCoreApplication::instance(), SLOT(quit()), actionCollection()); KStandardAction::preferences(this, SLOT(showConfiguration()), actionCollection()); setupGUI(); if (KrfbConfig::allowDesktopControl()) { m_ui.enableSharingCheckBox->setChecked(true); } setAutoSaveSettings(); } MainWindow::~MainWindow() { } void MainWindow::editPassword() { if(m_passwordEditable) { m_passwordEditable = false; m_ui.passwordEditButton->setIcon(QIcon::fromTheme("document-properties")); m_ui.passwordGridLayout->removeWidget(m_passwordLineEdit); InvitationsRfbServer::instance->setDesktopPassword( m_passwordLineEdit->text()); m_ui.passwordDisplayLabel->setText( InvitationsRfbServer::instance->desktopPassword()); m_passwordLineEdit->setVisible(false); } else { m_passwordEditable = true; m_ui.passwordEditButton->setIcon(QIcon::fromTheme("document-save")); m_ui.passwordGridLayout->addWidget(m_passwordLineEdit,0,0); m_passwordLineEdit->setText( InvitationsRfbServer::instance->desktopPassword()); m_passwordLineEdit->setVisible(true); m_passwordLineEdit->setFocus(Qt::MouseFocusReason); } } void MainWindow::editUnattendedPassword() { KNewPasswordDialog dialog(this); dialog.setPrompt(i18n("Enter a new password for Unattended Access")); if(dialog.exec()) { InvitationsRfbServer::instance->setUnattendedPassword(dialog.password()); } } void MainWindow::toggleDesktopSharing(bool enable) { if(enable) { if(!InvitationsRfbServer::instance->start()) { KMessageBox::error(this, i18n("Failed to start the krfb server. Desktop sharing " "will not work. Try setting another port in the settings " "and restart krfb.")); } } else { InvitationsRfbServer::instance->stop(); if(m_passwordEditable) { m_passwordEditable = false; m_passwordLineEdit->setVisible(false); m_ui.passwordEditButton->setIcon(QIcon::fromTheme("document-properties")); } } } void MainWindow::passwordChanged(const QString& password) { m_passwordLineEdit->setText(password); m_ui.passwordDisplayLabel->setText(password); } void MainWindow::aboutConnectionAddress() { KMessageBox::about(this, i18n("This field contains the address of your computer and the port number, separated by a colon.\n\nThe address is just a hint - you can use any address that can reach your computer.\n\nDesktop Sharing tries to guess your address from your network configuration, but does not always succeed in doing so.\n\nIf your computer is behind a firewall it may have a different address or be unreachable for other computers."), i18n("KDE Desktop Sharing")); } void MainWindow::aboutUnattendedMode() { KMessageBox::about(this, i18n("Any remote user with normal desktop sharing password will have to be authenticated.\n\nIf unattended access is on, and the remote user provides unattended mode password, desktop sharing access will be granted without explicit confirmation."), i18n("KDE Desktop Sharing")); } void MainWindow::showConfiguration() { static QString s_prevFramebufferPlugin; + static bool s_prevNoWallet; // ^^ needs to be static, because lambda will be called long time // after showConfiguration() ends, so auto variable would go out of scope // save previously selected framebuffer plugin config s_prevFramebufferPlugin = KrfbConfig::preferredFrameBufferPlugin(); + s_prevNoWallet = KrfbConfig::noWallet(); if (KConfigDialog::showDialog("settings")) { return; } KConfigDialog *dialog = new KConfigDialog(this, "settings", KrfbConfig::self()); dialog->addPage(new TCP, i18n("Network"), "network-wired"); dialog->addPage(new Security, i18n("Security"), "security-high"); dialog->addPage(new ConfigFramebuffer, i18n("Screen capture"), "video-display"); dialog->show(); connect(dialog, &KConfigDialog::settingsChanged, [this] () { // check if framebuffer plugin config has changed if (s_prevFramebufferPlugin != KrfbConfig::preferredFrameBufferPlugin()) { KMessageBox::information(this, i18n("To apply framebuffer plugin setting, " "you need to restart the program.")); } + // check if kwallet config has changed + if (s_prevNoWallet != KrfbConfig::noWallet()) { + // try to apply settings immediately + if (KrfbConfig::noWallet()) { + InvitationsRfbServer::instance->closeKWallet(); + } else { + InvitationsRfbServer::instance->openKWallet(); + // erase stored passwords from krfbconfig file + KConfigGroup securityConfigGroup(KSharedConfig::openConfig(), "Security"); + securityConfigGroup.deleteEntry("desktopPassword"); + securityConfigGroup.deleteEntry("unattendedPassword"); + } + } }); } void MainWindow::readProperties(const KConfigGroup& group) { if (group.readEntry("Visible", true)) { show(); } KMainWindow::readProperties(group); } void MainWindow::saveProperties(KConfigGroup& group) { group.writeEntry("Visible", isVisible()); KMainWindow::saveProperties(group); } diff --git a/krfb/ui/configsecurity.ui b/krfb/ui/configsecurity.ui index 93d59f3..531591b 100644 --- a/krfb/ui/configsecurity.ui +++ b/krfb/ui/configsecurity.ui @@ -1,41 +1,48 @@ Security 0 0 507 201 Allow remote connections to control your desktop true + + + + Do not store passwords using KDE wallet + + + Qt::Vertical 20 40