File indexing completed on 2024-04-14 04:53:33
0001 /* 0002 Copyright (C) 2009-2010 Collabora Ltd <info@collabora.co.uk> 0003 @author George Goldberg <george.goldberg@collabora.co.uk> 0004 @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk> 0005 Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it> 0006 Copyright (C) 2001-2003 by Tim Jansen <tim@tjansen.de> 0007 0008 This program is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU General Public 0010 License as published by the Free Software Foundation; either 0011 version 2 of the License, or (at your option) any later version. 0012 0013 This program is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0016 GNU General Public License for more details. 0017 0018 You should have received a copy of the GNU Lesser General Public License 0019 along with this program. If not, see <http://www.gnu.org/licenses/>. 0020 */ 0021 #include "invitationsrfbserver.h" 0022 #include "invitationsrfbclient.h" 0023 #include "krfbconfig.h" 0024 #include "krfbdebug.h" 0025 #include <QTimer> 0026 #include <QApplication> 0027 #include <QHostInfo> 0028 #include <QRandomGenerator> 0029 0030 #include <KLocalizedString> 0031 #include <KUser> 0032 #include <KStringHandler> 0033 #include <KWallet> 0034 0035 #include <KDNSSD/PublicService> 0036 0037 using KWallet::Wallet; 0038 0039 // used for KWallet folder name 0040 static const QString s_krfbFolderName(QStringLiteral("krfb")); 0041 0042 //static 0043 InvitationsRfbServer *InvitationsRfbServer::instance; 0044 0045 //static 0046 void InvitationsRfbServer::init() 0047 { 0048 instance = new InvitationsRfbServer; 0049 instance->m_publicService = new KDNSSD::PublicService( 0050 i18n("%1@%2 (shared desktop)", 0051 KUser().loginName(), 0052 QHostInfo::localHostName()), 0053 QStringLiteral("_rfb._tcp"), 0054 KrfbConfig::port()); 0055 instance->setListeningAddress("0.0.0.0"); 0056 instance->setListeningPort(KrfbConfig::port()); 0057 instance->setPasswordRequired(true); 0058 0059 instance->m_wallet = nullptr; 0060 if (KrfbConfig::noWallet()) { 0061 instance->walletOpened(false); 0062 } else { 0063 instance->openKWallet(); 0064 } 0065 } 0066 0067 const QString& InvitationsRfbServer::desktopPassword() const 0068 { 0069 return m_desktopPassword; 0070 } 0071 0072 void InvitationsRfbServer::setDesktopPassword(const QString& password) 0073 { 0074 m_desktopPassword = password; 0075 // this is called from GUI every time desktop password is edited. 0076 // make sure we save settings immediately each time 0077 saveSecuritySettings(); 0078 } 0079 0080 const QString& InvitationsRfbServer::unattendedPassword() const 0081 { 0082 return m_unattendedPassword; 0083 } 0084 0085 void InvitationsRfbServer::setUnattendedPassword(const QString& password) 0086 { 0087 m_unattendedPassword = password; 0088 // this is called from GUI every time unattended password is edited. 0089 // make sure we save settings immediately each time 0090 saveSecuritySettings(); 0091 } 0092 0093 bool InvitationsRfbServer::allowUnattendedAccess() const 0094 { 0095 return m_allowUnattendedAccess; 0096 } 0097 0098 bool InvitationsRfbServer::start() 0099 { 0100 if(RfbServer::start()) { 0101 if(KrfbConfig::publishService()) 0102 m_publicService->publishAsync(); 0103 return true; 0104 } 0105 return false; 0106 } 0107 0108 void InvitationsRfbServer::stop() 0109 { 0110 if(m_publicService->isPublished()) 0111 m_publicService->stop(); 0112 RfbServer::stop(); 0113 } 0114 0115 void InvitationsRfbServer::toggleUnattendedAccess(bool allow) 0116 { 0117 m_allowUnattendedAccess = allow; 0118 // this is called from GUI every time unattended access is toggled. 0119 // make sure we save settings immediately each time 0120 saveSecuritySettings(); 0121 } 0122 0123 InvitationsRfbServer::InvitationsRfbServer() 0124 { 0125 m_desktopPassword = readableRandomString(4) + QLatin1Char('-') + readableRandomString(3); 0126 m_unattendedPassword = readableRandomString(4) + QLatin1Char('-') + readableRandomString(3); 0127 KConfigGroup krfbConfig(KSharedConfig::openConfig(),QStringLiteral("Security")); 0128 m_allowUnattendedAccess = krfbConfig.readEntry( 0129 "allowUnattendedAccess", QVariant(false)).toBool(); 0130 } 0131 0132 InvitationsRfbServer::~InvitationsRfbServer() 0133 { 0134 InvitationsRfbServer::stop(); // calling virtual funcs in destructor is bad 0135 saveSecuritySettings(); 0136 // ^^ also saves passwords in kwallet, 0137 // do it before closing kwallet 0138 if (!KrfbConfig::noWallet() && m_wallet) { 0139 closeKWallet(); 0140 } 0141 } 0142 0143 PendingRfbClient* InvitationsRfbServer::newClient(rfbClientPtr client) 0144 { 0145 return new PendingInvitationsRfbClient(client, this); 0146 } 0147 0148 void InvitationsRfbServer::openKWallet() 0149 { 0150 m_wallet = Wallet::openWallet(Wallet::NetworkWallet(), 0, Wallet::Asynchronous); 0151 if (m_wallet) { 0152 connect(instance->m_wallet, &KWallet::Wallet::walletOpened, 0153 this, &InvitationsRfbServer::walletOpened); 0154 } 0155 } 0156 0157 void InvitationsRfbServer::closeKWallet() 0158 { 0159 if (m_wallet && m_wallet->isOpen()) { 0160 delete m_wallet; // closes the wallet 0161 m_wallet = nullptr; 0162 } 0163 } 0164 0165 void InvitationsRfbServer::walletOpened(bool opened) 0166 { 0167 QString desktopPassword; 0168 QString unattendedPassword; 0169 Q_ASSERT(m_wallet); 0170 0171 if (opened && m_wallet->hasFolder(s_krfbFolderName) && m_wallet->setFolder(s_krfbFolderName) ) { 0172 if (m_wallet->readPassword(QStringLiteral("desktopSharingPassword"), desktopPassword) == 0 && 0173 !desktopPassword.isEmpty()) { 0174 m_desktopPassword = desktopPassword; 0175 Q_EMIT passwordChanged(m_desktopPassword); 0176 } 0177 0178 if(m_wallet->readPassword(QStringLiteral("unattendedAccessPassword"), unattendedPassword) == 0 && 0179 !unattendedPassword.isEmpty()) { 0180 m_unattendedPassword = unattendedPassword; 0181 } 0182 0183 } else { 0184 0185 qCDebug(KRFB) << "Could not open KWallet, Falling back to config file"; 0186 KConfigGroup krfbConfig(KSharedConfig::openConfig(),QStringLiteral("Security")); 0187 0188 desktopPassword = KStringHandler::obscure(krfbConfig.readEntry( 0189 "desktopPassword", QString())); 0190 if(!desktopPassword.isEmpty()) { 0191 m_desktopPassword = desktopPassword; 0192 Q_EMIT passwordChanged(m_desktopPassword); 0193 } 0194 0195 unattendedPassword = KStringHandler::obscure(krfbConfig.readEntry( 0196 "unattendedPassword", QString())); 0197 if(!unattendedPassword.isEmpty()) { 0198 m_unattendedPassword = unattendedPassword; 0199 } 0200 0201 } 0202 } 0203 0204 // a random string that doesn't contain i, I, o, O, 1, l, 0 0205 // based on KRandom::randomString() 0206 QString InvitationsRfbServer::readableRandomString(int length) 0207 { 0208 QString str; 0209 while (length) { 0210 int r = QRandomGenerator::global()->bounded(62); 0211 r += 48; 0212 if (r > 57) { 0213 r += 7; 0214 } 0215 if (r > 90) { 0216 r += 6; 0217 } 0218 char c = char(r); 0219 if ((c == 'i') || 0220 (c == 'I') || 0221 (c == '1') || 0222 (c == 'l') || 0223 (c == 'o') || 0224 (c == 'O') || 0225 (c == '0')) { 0226 continue; 0227 } 0228 str += QLatin1Char(c); 0229 length--; 0230 } 0231 return str; 0232 } 0233 0234 // one place to deal with all security configuration 0235 void InvitationsRfbServer::saveSecuritySettings() 0236 { 0237 KConfigGroup secConfigGroup(KSharedConfig::openConfig(), QStringLiteral("Security")); 0238 secConfigGroup.writeEntry("allowUnattendedAccess", m_allowUnattendedAccess); 0239 if (KrfbConfig::noWallet()) { 0240 // save passwords in config file only if not using kwallet integration 0241 secConfigGroup.writeEntry("desktopPassword", KStringHandler::obscure(m_desktopPassword)); 0242 secConfigGroup.writeEntry("unattendedPassword", KStringHandler::obscure(m_unattendedPassword)); 0243 } else { 0244 // using KWallet, erase possibly stored passwords from krfbrc file 0245 secConfigGroup.deleteEntry("desktopPassword"); 0246 secConfigGroup.deleteEntry("unattendedPassword"); 0247 // update passwords in kwallet 0248 if (m_wallet && m_wallet->isOpen()) { 0249 if (!m_wallet->hasFolder(s_krfbFolderName)) { 0250 m_wallet->createFolder(s_krfbFolderName); 0251 } 0252 if (m_wallet->currentFolder() != s_krfbFolderName) { 0253 m_wallet->setFolder(s_krfbFolderName); 0254 } 0255 m_wallet->writePassword(QStringLiteral("desktopSharingPassword"), m_desktopPassword); 0256 m_wallet->writePassword(QStringLiteral("unattendedAccessPassword"), m_unattendedPassword); 0257 } 0258 } 0259 KrfbConfig::self()->save(); 0260 }