1 /*
2  * synergy -- mouse and keyboard sharing utility
3  * Copyright (C) 2012-2016 Symless Ltd.
4  * Copyright (C) 2008 Volker Lanz (vl@fidra.de)
5  *
6  * This package is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * found in the file LICENSE that should have accompanied this file.
9  *
10  * This package is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "QSynergyApplication.h"
20 #include "AppConfig.h"
21 #include "QUtility.h"
22 
23 #include <QtCore>
24 #include <QtNetwork>
25 #include <QtWidgets/QMessageBox>
26 #include <QPushButton>
27 
28 #include "ConfigWriter.h"
29 #include "SslCertificate.h"
30 
31 using GUI::Config::ConfigWriter;
32 #if defined(Q_OS_WIN)
33 const char AppConfig::m_SynergysName[] = "synergys.exe";
34 const char AppConfig::m_SynergycName[] = "synergyc.exe";
35 const char AppConfig::m_SynergyLogDir[] = "log/";
36 const char AppConfig::synergyConfigName[] = "synergy.sgc";
37 #define DEFAULT_PROCESS_MODE Service
38 #else
39 const char AppConfig::m_SynergysName[] = "synergys";
40 const char AppConfig::m_SynergycName[] = "synergyc";
41 const char AppConfig::m_SynergyLogDir[] = "/var/log/";
42 const char AppConfig::synergyConfigName[] = "synergy.conf";
43 #define DEFAULT_PROCESS_MODE Desktop
44 #endif
45 
46 const ElevateMode defaultElevateMode = ElevateAsNeeded;
47 
48 const char* AppConfig::m_SynergySettingsName[] = {
49         "screenName",
50         "port",
51         "interface",
52         "logLevel2",
53         "logToFile",
54         "logFilename",
55         "wizardLastRun",
56         "language",
57         "startedBefore",
58         "autoConfig",
59         "autoConfigServer",
60         "elevateMode",
61         "elevateModeEnum",
62         "edition",
63         "cryptoEnabled",
64         "autoHide",
65         "serialKey",
66         "lastVersion",
67         "lastExpiringWarningTime",
68         "activationHasRun",
69         "minimizeToTray",
70         "ActivateEmail",
71         "loadFromSystemScope",
72         "groupServerChecked",
73         "useExternalConfig",
74         "configFile",
75         "useInternalConfig",
76         "groupClientChecked",
77         "serverHostname",
78         "tlsCertPath",
79         "tlsKeyLength",
80 };
81 
82 static const char* logLevelNames[] =
83 {
84     "INFO",
85     "DEBUG",
86     "DEBUG1",
87     "DEBUG2"
88 };
89 
AppConfig()90 AppConfig::AppConfig() :
91     m_ScreenName(),
92     m_Port(24800),
93     m_Interface(),
94     m_LogLevel(0),
95     m_WizardLastRun(0),
96     m_ProcessMode(DEFAULT_PROCESS_MODE),
97     m_AutoConfig(true),
98     m_ElevateMode(defaultElevateMode),
99     m_CryptoEnabled(false),
100     m_AutoHide(false),
101     m_LastExpiringWarningTime(0),
102     m_AutoConfigServer(),
103     m_MinimizeToTray(false),
104     m_Edition(kUnregistered),
105     m_LogToFile(),
106     m_StartedBefore(),
107     m_ActivationHasRun(),
108     m_ServerGroupChecked(),
109     m_UseExternalConfig(),
110     m_UseInternalConfig(),
111     m_ClientGroupChecked(),
112     m_LoadFromSystemScope()
113 {
114 
115     auto writer = ConfigWriter::make();
116 
117     //Register this class to receive global load and saves
118     writer->registerClass(this);
119     writer->globalLoad();
120 
121     //User settings exist and the load from system scope variable is true
122     if (writer->hasSetting(settingName(kLoadSystemSettings), ConfigWriter::kUser)) {
123         setLoadFromSystemScope(m_LoadFromSystemScope);
124     }
125     //If user setting don't exist but system ones do, load the system settings
126     else if (writer->hasSetting(settingName(kScreenName), ConfigWriter::kSystem)) {
127         setLoadFromSystemScope(true);
128     }
129 }
130 
screenName() const131 const QString &AppConfig::screenName() const { return m_ScreenName; }
132 
port() const133 int AppConfig::port() const { return m_Port; }
134 
networkInterface() const135 const QString &AppConfig::networkInterface() const { return m_Interface; }
136 
logLevel() const137 int AppConfig::logLevel() const { return m_LogLevel; }
138 
logToFile() const139 bool AppConfig::logToFile() const { return m_LogToFile; }
140 
logFilename() const141 const QString &AppConfig::logFilename() const { return m_LogFilename; }
142 
synergyLogDir() const143 QString AppConfig::synergyLogDir() const
144 {
145     // by default log to home dir
146     return QDir::home().absolutePath() + "/";
147 }
148 
synergyProgramDir() const149 QString AppConfig::synergyProgramDir() const
150 {
151     // synergy binaries should be in the same dir.
152     return QCoreApplication::applicationDirPath() + "/";
153 }
154 
persistLogDir()155 void AppConfig::persistLogDir()
156 {
157     QDir dir = synergyLogDir();
158 
159     // persist the log directory
160     if (!dir.exists())
161     {
162         dir.mkpath(dir.path());
163     }
164 }
165 
logFilenameCmd() const166 const QString AppConfig::logFilenameCmd() const
167 {
168     QString filename = m_LogFilename;
169 #if defined(Q_OS_WIN)
170     // wrap in quotes in case username contains spaces.
171     filename = QString("\"%1\"").arg(filename);
172 #endif
173     return filename;
174 }
175 
logLevelText() const176 QString AppConfig::logLevelText() const
177 {
178     return logLevelNames[logLevel()];
179 }
180 
processMode() const181 ProcessMode AppConfig::processMode() const { return m_ProcessMode; }
182 
wizardShouldRun() const183 bool AppConfig::wizardShouldRun() const { return m_WizardLastRun < kWizardVersion; }
184 
language() const185 const QString &AppConfig::language() const { return m_Language; }
186 
startedBefore() const187 bool AppConfig::startedBefore() const { return m_StartedBefore; }
188 
autoConfig() const189 bool AppConfig::autoConfig() const {
190 #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG)
191     return m_AutoConfig;
192 #else
193     // always disable auto config for enterprise edition.
194     return false;
195 #endif
196 }
197 
autoConfigServer() const198 QString AppConfig::autoConfigServer() const { return m_AutoConfigServer; }
199 
loadSettings()200 void AppConfig::loadSettings()
201 {
202     m_ScreenName        = loadSetting(kScreenName, QHostInfo::localHostName()).toString();
203     if (m_ScreenName.isEmpty()) {
204        m_ScreenName = QHostInfo::localHostName();
205     }
206 
207     m_Port              = loadSetting(kPort, 24800).toInt();
208     m_Interface         = loadSetting(kInterfaceSetting).toString();
209     m_LogLevel          = loadSetting(kLogLevel, 0).toInt();
210     m_LogToFile         = loadSetting(kLogToFile, false).toBool();
211     m_LogFilename       = loadSetting(kLogFilename, synergyLogDir() + "synergy.log").toString();
212     m_WizardLastRun     = loadCommonSetting(kWizardLastRun, 0).toInt();
213     m_Language          = loadSetting(kLanguage, QLocale::system().name()).toString();
214     m_StartedBefore     = loadSetting(kStartedBefore, false).toBool();
215     m_AutoConfig        = loadSetting(kAutoConfig, false).toBool();
216     m_AutoConfigServer  = loadSetting(kAutoConfigServer, "").toString();
217 
218     {   //Scope related code together
219         // TODO Investigate why kElevateModeEnum isn't loaded fully
220         QVariant elevateMode = loadSetting(kElevateModeEnum);
221         if (!elevateMode.isValid()) {
222             elevateMode = loadSetting(kElevateModeSetting,
223                                       QVariant(static_cast<int>(defaultElevateMode)));
224         }
225         m_ElevateMode        = static_cast<ElevateMode>(elevateMode.toInt());
226     }
227 
228     m_ActivateEmail             = loadSetting(kActivateEmail, "").toString();
229     m_CryptoEnabled             = loadSetting(kCryptoEnabled, true).toBool();
230     m_AutoHide                  = loadSetting(kAutoHide, false).toBool();
231     m_lastVersion               = loadSetting(kLastVersion, "Unknown").toString();
232     m_LastExpiringWarningTime   = loadSetting(kLastExpireWarningTime, 0).toInt();
233     m_ActivationHasRun          = loadSetting(kActivationHasRun, false).toBool();
234     m_MinimizeToTray            = loadSetting(kMinimizeToTray, false).toBool();
235     m_LoadFromSystemScope       = loadCommonSetting(kLoadSystemSettings, false).toBool();
236     m_ServerGroupChecked        = loadSetting(kGroupServerCheck, false).toBool();
237     m_UseExternalConfig         = loadSetting(kUseExternalConfig, false).toBool();
238     m_ConfigFile                = loadSetting(kConfigFile, QDir::homePath() + "/" + synergyConfigName).toString();
239     m_UseInternalConfig         = loadSetting(kUseInternalConfig, false).toBool();
240     m_ClientGroupChecked        = loadSetting(kGroupClientCheck, false).toBool();
241     m_ServerHostname            = loadSetting(kServerHostname).toString();
242 
243     //only change the serial key if the settings being loaded contains a key
244     bool updateSerial = ConfigWriter::make()
245             ->hasSetting(settingName(kLoadSystemSettings),ConfigWriter::kCurrent);
246     //if the setting exists and is not empty
247     updateSerial = updateSerial && !loadSetting(kSerialKey, "").toString().trimmed().isEmpty();
248 
249     if (updateSerial) {
250         m_Serialkey                 = loadSetting(kSerialKey, "").toString().trimmed();
251         m_Edition                   = static_cast<Edition>(loadSetting(kEditionSetting, kUnregistered).toInt());
252     }
253 
254     //Set the default path of the TLS certificate file in the users DIR
255     QString certificateFilename = QString("%1/%2/%3").arg(m_CoreInterface.getProfileDir(),
256                                                           "SSL",
257                                                           "Synergy.pem");
258 
259     m_TLSCertificatePath        = loadSetting(kTLSCertPath, certificateFilename).toString();
260     m_TLSKeyLength              = loadSetting(kTLSKeyLength, "2048").toString();
261 
262     if (getCryptoEnabled()) {
263         generateCertificate();
264     }
265 
266 }
267 
saveSettings()268 void AppConfig::saveSettings()
269 {
270     setCommonSetting(kWizardLastRun, m_WizardLastRun);
271     setCommonSetting(kLoadSystemSettings, m_LoadFromSystemScope);
272 
273     if (isWritable()) {
274         setSetting(kScreenName, m_ScreenName);
275         setSetting(kPort, m_Port);
276         setSetting(kInterfaceSetting, m_Interface);
277         setSetting(kLogLevel, m_LogLevel);
278         setSetting(kLogToFile, m_LogToFile);
279         setSetting(kLogFilename, m_LogFilename);
280         setSetting(kLanguage, m_Language);
281         setSetting(kStartedBefore, m_StartedBefore);
282         setSetting(kAutoConfig, m_AutoConfig);
283         setSetting(kAutoConfigServer, m_AutoConfigServer);
284         // Refer to enum ElevateMode declaration for insight in to why this
285         // flag is mapped this way
286         setSetting(kElevateModeSetting, m_ElevateMode == ElevateAlways);
287         setSetting(kElevateModeEnum, static_cast<int>(m_ElevateMode));
288         setSetting(kEditionSetting, m_Edition);
289         setSetting(kCryptoEnabled, m_CryptoEnabled);
290         setSetting(kAutoHide, m_AutoHide);
291         setSetting(kSerialKey, m_Serialkey);
292         setSetting(kLastVersion, m_lastVersion);
293         setSetting(kLastExpireWarningTime, m_LastExpiringWarningTime);
294         setSetting(kActivationHasRun, m_ActivationHasRun);
295         setSetting(kMinimizeToTray, m_MinimizeToTray);
296         setSetting(kGroupServerCheck, m_ServerGroupChecked);
297         setSetting(kUseExternalConfig, m_UseExternalConfig);
298         setSetting(kConfigFile, m_ConfigFile);
299         setSetting(kUseInternalConfig, m_UseInternalConfig);
300         setSetting(kGroupClientCheck, m_ClientGroupChecked);
301         setSetting(kServerHostname, m_ServerHostname);
302     }
303 
304     m_unsavedChanges = false;
305 }
306 
307 #ifndef SYNERGY_ENTERPRISE
activationHasRun() const308 bool AppConfig::activationHasRun() const
309 {
310     return m_ActivationHasRun;
311 }
312 
activationHasRun(bool value)313 AppConfig& AppConfig::activationHasRun(bool value)
314 {
315     m_ActivationHasRun = value;
316     return *this;
317 }
318 #endif
319 
lastVersion() const320 QString AppConfig::lastVersion() const
321 {
322     return m_lastVersion;
323 }
324 
setLastVersion(const QString & version)325 void AppConfig::setLastVersion(const QString& version) {
326     setSettingModified(m_lastVersion, version);
327 }
328 
setScreenName(const QString & s)329 void AppConfig::setScreenName(const QString &s) {
330     setSettingModified(m_ScreenName, s);
331     emit screenNameChanged();
332 }
333 
setPort(int i)334 void AppConfig::setPort(int i) {
335     setSettingModified(m_Port, i);
336 }
337 
setNetworkInterface(const QString & s)338 void AppConfig::setNetworkInterface(const QString &s) {
339     setSettingModified(m_Interface, s);
340 }
341 
setLogLevel(int i)342 void AppConfig::setLogLevel(int i) {
343     setSettingModified(m_LogLevel, i);
344 }
345 
setLogToFile(bool b)346 void AppConfig::setLogToFile(bool b) {
347     setSettingModified(m_LogToFile, b);
348 }
349 
setLogFilename(const QString & s)350 void AppConfig::setLogFilename(const QString &s) {
351     setSettingModified(m_LogFilename, s);
352 }
353 
setWizardHasRun()354 void AppConfig::setWizardHasRun() {
355     setSettingModified(m_WizardLastRun, kWizardVersion);
356 }
357 
setLanguage(const QString & language)358 void AppConfig::setLanguage(const QString& language) {
359     setSettingModified(m_Language, language);
360 }
361 
setStartedBefore(bool b)362 void AppConfig::setStartedBefore(bool b) {
363     setSettingModified(m_StartedBefore, b);
364 }
365 
setElevateMode(ElevateMode em)366 void AppConfig::setElevateMode(ElevateMode em) {
367     setSettingModified(m_ElevateMode, em);
368 }
369 
setAutoConfig(bool autoConfig)370 void AppConfig::setAutoConfig(bool autoConfig)
371 {
372     setSettingModified(m_AutoConfig, autoConfig);
373     emit zeroConfToggled();
374 }
375 
setAutoConfigServer(const QString & autoConfigServer)376 void AppConfig::setAutoConfigServer(const QString& autoConfigServer)
377 {
378     setSettingModified(m_AutoConfigServer, autoConfigServer);
379 }
380 
381 #ifndef SYNERGY_ENTERPRISE
setEdition(Edition e)382 void AppConfig::setEdition(Edition e) {
383     setSettingModified(m_Edition, e);
384     setCommonSetting(kEditionSetting, m_Edition);
385 }
386 
edition() const387 Edition AppConfig::edition() const { return m_Edition; }
388 
setSerialKey(const QString & serial)389 void AppConfig::setSerialKey(const QString& serial) {
390     setSettingModified(m_Serialkey, serial);
391     setCommonSetting(kSerialKey, m_Serialkey);
392 }
393 
clearSerialKey()394 void AppConfig::clearSerialKey()
395 {
396     m_Serialkey.clear();
397 }
398 
serialKey()399 QString AppConfig::serialKey() { return m_Serialkey; }
400 
lastExpiringWarningTime() const401 int AppConfig::lastExpiringWarningTime() const { return m_LastExpiringWarningTime; }
402 
setLastExpiringWarningTime(int newValue)403 void AppConfig::setLastExpiringWarningTime(int newValue) {
404     setSettingModified(m_LastExpiringWarningTime, newValue);
405 }
406 #endif
407 
synergysName() const408 QString AppConfig::synergysName() const { return m_SynergysName; }
409 
synergycName() const410 QString AppConfig::synergycName() const { return m_SynergycName; }
411 
elevateMode()412 ElevateMode AppConfig::elevateMode()
413 {
414     return m_ElevateMode;
415 }
416 
setCryptoEnabled(bool newValue)417 void AppConfig::setCryptoEnabled(bool newValue) {
418     if (m_CryptoEnabled != newValue && newValue){
419         generateCertificate();
420     }
421     else {
422         emit sslToggled();
423     }
424     setSettingModified(m_CryptoEnabled, newValue);
425 }
426 
isCryptoAvailable() const427 bool AppConfig::isCryptoAvailable() const {
428     bool result {true};
429 
430 #ifndef SYNERGY_ENTERPRISE
431     result = (edition() == kPro || edition() == kPro_China || edition() == kBusiness);
432 #endif
433 
434     return result;
435 }
436 
getCryptoEnabled() const437 bool AppConfig::getCryptoEnabled() const {
438     return isCryptoAvailable() && m_CryptoEnabled;
439 }
440 
setAutoHide(bool b)441 void AppConfig::setAutoHide(bool b) {
442     setSettingModified(m_AutoHide, b);
443 }
444 
getAutoHide()445 bool AppConfig::getAutoHide() { return m_AutoHide; }
446 
setMinimizeToTray(bool newValue)447 void AppConfig::setMinimizeToTray(bool newValue) {
448     setSettingModified(m_MinimizeToTray, newValue);
449 }
450 
getLanguageSync() const451 bool AppConfig::getLanguageSync() const { return m_LanguageSync; }
452 
setLanguageSync(bool newValue)453 void AppConfig::setLanguageSync(bool newValue) {
454     setSettingModified(m_LanguageSync, newValue);
455 }
456 
getMinimizeToTray()457 bool AppConfig::getMinimizeToTray() { return m_MinimizeToTray; }
458 
settingName(AppConfig::Setting name)459 QString AppConfig::settingName(AppConfig::Setting name) {
460     return m_SynergySettingsName[name];
461 }
462 
463 template<typename T>
setSetting(AppConfig::Setting name,T value)464 void AppConfig::setSetting(AppConfig::Setting name, T value) {
465     ConfigWriter::make()->setSetting(settingName(name), value);
466 }
467 
468 template<typename T>
setCommonSetting(AppConfig::Setting name,T value)469 void AppConfig::setCommonSetting(AppConfig::Setting name, T value) {
470     ConfigWriter::make()->setSetting(settingName(name), value, ConfigWriter::kUser);
471     ConfigWriter::make()->setSetting(settingName(name), value, ConfigWriter::kSystem);
472 }
473 
loadSetting(AppConfig::Setting name,const QVariant & defaultValue)474 QVariant AppConfig::loadSetting(AppConfig::Setting name, const QVariant& defaultValue) {
475     return ConfigWriter::make()->loadSetting(settingName(name), defaultValue);
476 }
477 
loadCommonSetting(AppConfig::Setting name,const QVariant & defaultValue) const478 QVariant AppConfig::loadCommonSetting(AppConfig::Setting name, const QVariant& defaultValue) const {
479     QVariant result(defaultValue);
480     QString setting(settingName(name));
481     auto& writer = *ConfigWriter::make();
482 
483     if (writer.hasSetting(setting)) {
484         result = writer.loadSetting(setting, defaultValue);
485     }
486     else if (writer.getScope() == ConfigWriter::kSystem ) {
487         if (writer.hasSetting(setting, ConfigWriter::kUser)) {
488             result = writer.loadSetting(setting, defaultValue, ConfigWriter::kUser);
489         }
490     }
491     else if (writer.hasSetting(setting, ConfigWriter::kSystem)){
492         result = writer.loadSetting(setting, defaultValue, ConfigWriter::kSystem);
493     }
494 
495     return result;
496 }
497 
loadScope(ConfigWriter::Scope scope) const498 void AppConfig::loadScope(ConfigWriter::Scope scope) const {
499    auto writer = ConfigWriter::make();
500 
501    if (writer->getScope() != scope) {
502       writer->setScope(scope);
503       if (writer->hasSetting(settingName(kScreenName), writer->getScope())) {
504           //If the user already has settings, then load them up now.
505           writer->globalLoad();
506       }
507    }
508 }
509 
setLoadFromSystemScope(bool value)510 void AppConfig::setLoadFromSystemScope(bool value) {
511 
512    if (value) {
513       loadScope(ConfigWriter::kSystem);
514    }
515    else {
516       loadScope(ConfigWriter::kUser);
517    }
518 
519    /*
520     * It's very imprortant to set this variable after loadScope
521     * because during scope loading this variable can be rewritten with old value
522    */
523    m_LoadFromSystemScope = value;
524 }
525 
isWritable() const526 bool  AppConfig::isWritable() const {
527     return ConfigWriter::make()->isWritable();
528 }
529 
isSystemScoped() const530 bool AppConfig::isSystemScoped() const {
531     return ConfigWriter::make()->getScope() == ConfigWriter::kSystem;
532 }
533 
getServerGroupChecked() const534 bool AppConfig::getServerGroupChecked() const {
535     return m_ServerGroupChecked;
536 }
537 
getUseExternalConfig() const538 bool AppConfig::getUseExternalConfig() const {
539     return m_UseExternalConfig;
540 }
541 
getConfigFile() const542 const QString& AppConfig::getConfigFile() const {
543     return m_ConfigFile;
544 }
545 
getUseInternalConfig() const546 bool AppConfig::getUseInternalConfig() const {
547     return m_UseInternalConfig;
548 }
549 
getClientGroupChecked() const550 bool AppConfig::getClientGroupChecked() const {
551     return m_ClientGroupChecked;
552 }
553 
getServerHostname() const554 QString AppConfig::getServerHostname() const {
555     return m_ServerHostname;
556 }
557 
setServerGroupChecked(bool newValue)558 void AppConfig::setServerGroupChecked(bool newValue) {
559     setSettingModified(m_ServerGroupChecked, newValue);
560 }
561 
setUseExternalConfig(bool newValue)562 void AppConfig::setUseExternalConfig(bool newValue) {
563     setSettingModified(m_UseExternalConfig, newValue);
564 }
565 
setConfigFile(const QString & newValue)566 void AppConfig::setConfigFile(const QString& newValue) {
567     setSettingModified(m_ConfigFile, newValue);
568 }
569 
setUseInternalConfig(bool newValue)570 void AppConfig::setUseInternalConfig(bool newValue) {
571     setSettingModified(m_UseInternalConfig, newValue);
572 }
573 
setClientGroupChecked(bool newValue)574 void AppConfig::setClientGroupChecked(bool newValue) {
575     setSettingModified(m_ClientGroupChecked, newValue);
576 }
577 
setServerHostname(const QString & newValue)578 void AppConfig::setServerHostname(const QString& newValue) {
579     setSettingModified(m_ServerHostname, newValue);
580 }
581 
582 template<typename T>
setSettingModified(T & variable,const T & newValue)583 void AppConfig::setSettingModified(T &variable, const T& newValue) {
584     if (variable != newValue)
585     {
586         variable = newValue;
587         m_unsavedChanges = true;
588     }
589 }
590 
setTLSCertPath(const QString & path)591 void AppConfig::setTLSCertPath(const QString& path) {
592     m_TLSCertificatePath = path;
593 }
594 
getTLSCertPath() const595 QString AppConfig::getTLSCertPath() const {
596     return m_TLSCertificatePath;
597 }
598 
getTLSKeyLength() const599 QString AppConfig::getTLSKeyLength() const {
600     return m_TLSKeyLength;
601 }
602 
setTLSKeyLength(const QString & length)603 void AppConfig::setTLSKeyLength(const QString& length) {
604     if (m_TLSKeyLength != length) {
605         m_TLSKeyLength = length;
606         generateCertificate(true);
607     }
608 }
609 
generateCertificate(bool forceGeneration) const610 void AppConfig::generateCertificate(bool forceGeneration) const {
611     SslCertificate sslCertificate;
612     sslCertificate.generateCertificate(getTLSCertPath(), getTLSKeyLength(), forceGeneration);
613     emit sslToggled();
614 }
615 
616 
617