mirror of
https://github.com/KDE/krfb
synced 2026-07-01 07:31:16 -07:00
255 lines
7.8 KiB
C++
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;
|
|
}
|
|
}
|