Files
krfb/krfb/invitationsrfbserver.cpp

255 lines
7.8 KiB
C++

/*
SPDX-FileCopyrightText: 2009-2010 Collabora Ltd <info@collabora.co.uk>
SPDX-FileContributor: George Goldberg <george.goldberg@collabora.co.uk>
SPDX-FileContributor: George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
SPDX-FileCopyrightText: 2007 Alessandro Praduroux <pradu@pradu.it>
SPDX-FileCopyrightText: 2001-2003 Tim Jansen <tim@tjansen.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "invitationsrfbserver.h"
#include "invitationsrfbclient.h"
#include "krfbconfig.h"
#include "krfbdebug.h"
#include <QTimer>
#include <QApplication>
#include <QHostInfo>
#include <QRandomGenerator>
#include <KLocalizedString>
#include <KUser>
#include <KStringHandler>
#include <KWallet>
#include <KDNSSD/PublicService>
using KWallet::Wallet;
// used for KWallet folder name
static const QString s_krfbFolderName(QStringLiteral("krfb"));
//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()),
QStringLiteral("_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->readPasswordFromConfig();
} else {
instance->openKWallet();
}
}
const QString& InvitationsRfbServer::desktopPassword() const
{
return m_desktopPassword;
}
void InvitationsRfbServer::setDesktopPassword(const QString& password)
{
m_desktopPassword = password;
// this is called from GUI every time desktop password is edited.
// make sure we save settings immediately each time
saveSecuritySettings();
}
const QString& InvitationsRfbServer::unattendedPassword() const
{
return m_unattendedPassword;
}
void InvitationsRfbServer::setUnattendedPassword(const QString& password)
{
m_unattendedPassword = password;
// this is called from GUI every time unattended password is edited.
// make sure we save settings immediately each time
saveSecuritySettings();
}
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;
// this is called from GUI every time unattended access is toggled.
// make sure we save settings immediately each time
saveSecuritySettings();
}
InvitationsRfbServer::InvitationsRfbServer()
{
m_desktopPassword = readableRandomString(4) + QLatin1Char('-') + readableRandomString(3);
m_unattendedPassword = readableRandomString(4) + QLatin1Char('-') + readableRandomString(3);
KConfigGroup krfbConfig(KSharedConfig::openConfig(),QStringLiteral("Security"));
m_allowUnattendedAccess = krfbConfig.readEntry(
"allowUnattendedAccess", QVariant(false)).toBool();
}
InvitationsRfbServer::~InvitationsRfbServer()
{
InvitationsRfbServer::stop(); // calling virtual funcs in destructor is bad
saveSecuritySettings();
// ^^ also saves passwords in kwallet,
// do it before closing kwallet
if (!KrfbConfig::noWallet() && m_wallet) {
closeKWallet();
}
}
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()) {
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(s_krfbFolderName) && m_wallet->setFolder(s_krfbFolderName) ) {
if (m_wallet->readPassword(QStringLiteral("desktopSharingPassword"), desktopPassword) == 0 &&
!desktopPassword.isEmpty()) {
m_desktopPassword = desktopPassword;
Q_EMIT passwordChanged(m_desktopPassword);
}
if(m_wallet->readPassword(QStringLiteral("unattendedAccessPassword"), unattendedPassword) == 0 &&
!unattendedPassword.isEmpty()) {
m_unattendedPassword = unattendedPassword;
}
} else {
qCDebug(KRFB) << "Could not open KWallet, Falling back to config file";
readPasswordFromConfig();
}
}
// 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 = QRandomGenerator::global()->bounded(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 += QLatin1Char(c);
length--;
}
return str;
}
// one place to deal with all security configuration
void InvitationsRfbServer::saveSecuritySettings()
{
KConfigGroup secConfigGroup(KSharedConfig::openConfig(), QStringLiteral("Security"));
secConfigGroup.writeEntry("allowUnattendedAccess", m_allowUnattendedAccess);
if (KrfbConfig::noWallet()) {
// save passwords in config file only if not using kwallet integration
secConfigGroup.writeEntry("desktopPassword", KStringHandler::obscure(m_desktopPassword));
secConfigGroup.writeEntry("unattendedPassword", KStringHandler::obscure(m_unattendedPassword));
} else {
// using KWallet, erase possibly stored passwords from krfbrc file
secConfigGroup.deleteEntry("desktopPassword");
secConfigGroup.deleteEntry("unattendedPassword");
// update passwords in kwallet
if (m_wallet && m_wallet->isOpen()) {
if (!m_wallet->hasFolder(s_krfbFolderName)) {
m_wallet->createFolder(s_krfbFolderName);
}
if (m_wallet->currentFolder() != s_krfbFolderName) {
m_wallet->setFolder(s_krfbFolderName);
}
m_wallet->writePassword(QStringLiteral("desktopSharingPassword"), m_desktopPassword);
m_wallet->writePassword(QStringLiteral("unattendedAccessPassword"), m_unattendedPassword);
}
}
KrfbConfig::self()->save();
}
void InvitationsRfbServer::readPasswordFromConfig()
{
QString desktopPassword;
QString unattendedPassword;
KConfigGroup krfbConfig(KSharedConfig::openConfig(),QStringLiteral("Security"));
desktopPassword = KStringHandler::obscure(krfbConfig.readEntry(
"desktopPassword", QString()));
if(!desktopPassword.isEmpty()) {
m_desktopPassword = desktopPassword;
Q_EMIT passwordChanged(m_desktopPassword);
}
unattendedPassword = KStringHandler::obscure(krfbConfig.readEntry(
"unattendedPassword", QString()));
if(!unattendedPassword.isEmpty()) {
m_unattendedPassword = unattendedPassword;
}
}