a59d8972ffe0dfc1d47088840564d093dfc119d0
[quassel.git] / src / core / core.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2018 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program 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, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #include "core.h"
22
23 #include <algorithm>
24
25 #include <QCoreApplication>
26
27 #include "coreauthhandler.h"
28 #include "coresession.h"
29 #include "coresettings.h"
30 #include "internalpeer.h"
31 #include "logmessage.h"
32 #include "network.h"
33 #include "postgresqlstorage.h"
34 #include "quassel.h"
35 #include "sqlauthenticator.h"
36 #include "sqlitestorage.h"
37 #include "types.h"
38 #include "util.h"
39
40 #ifdef HAVE_LDAP
41 #    include "ldapauthenticator.h"
42 #endif
43
44 // migration related
45 #include <QFile>
46 #ifdef Q_OS_WIN
47 #    include <windows.h>
48 #else
49 #    include <termios.h>
50 #    include <unistd.h>
51 #endif /* Q_OS_WIN */
52
53 // ==============================
54 //  Custom Events
55 // ==============================
56 const int Core::AddClientEventId = QEvent::registerEventType();
57
58 class AddClientEvent : public QEvent
59 {
60 public:
61     AddClientEvent(RemotePeer* p, UserId uid)
62         : QEvent(QEvent::Type(Core::AddClientEventId))
63         , peer(p)
64         , userId(uid)
65     {}
66     RemotePeer* peer;
67     UserId userId;
68 };
69
70 // ==============================
71 //  Core
72 // ==============================
73
74 Core::Core()
75     : Singleton<Core>{this}
76 {
77     Q_INIT_RESOURCE(sql);
78
79     // Parent all QObject-derived attributes, so when the Core instance gets moved into another
80     // thread, they get moved with it
81     _server.setParent(this);
82     _v6server.setParent(this);
83     _storageSyncTimer.setParent(this);
84 }
85
86 Core::~Core()
87 {
88     qDeleteAll(_connectingClients);
89     qDeleteAll(_sessions);
90     syncStorage();
91 }
92
93 void Core::init()
94 {
95     _startTime = QDateTime::currentDateTime().toUTC();  // for uptime :)
96
97     // check settings version
98     // so far, we only have 1
99     CoreSettings s;
100     if (s.version() != 1) {
101         throw ExitException{EXIT_FAILURE, tr("Invalid core settings version!")};
102     }
103
104     // Set up storage and authentication backends
105     registerStorageBackends();
106     registerAuthenticators();
107
108     QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
109     bool config_from_environment = Quassel::isOptionSet("config-from-environment");
110
111     QString db_backend;
112     QVariantMap db_connectionProperties;
113
114     QString auth_authenticator;
115     QVariantMap auth_properties;
116
117     bool writeError = false;
118
119     if (config_from_environment) {
120         db_backend = environment.value("DB_BACKEND");
121         auth_authenticator = environment.value("AUTH_AUTHENTICATOR");
122     }
123     else {
124         CoreSettings cs;
125
126         QVariantMap dbsettings = cs.storageSettings().toMap();
127         db_backend = dbsettings.value("Backend").toString();
128         db_connectionProperties = dbsettings.value("ConnectionProperties").toMap();
129
130         QVariantMap authSettings = cs.authSettings().toMap();
131         auth_authenticator = authSettings.value("Authenticator", "Database").toString();
132         auth_properties = authSettings.value("AuthProperties").toMap();
133
134         writeError = !cs.isWritable();
135     }
136
137     try {
138         _configured = initStorage(db_backend, db_connectionProperties, environment, config_from_environment);
139         if (_configured) {
140             _configured = initAuthenticator(auth_authenticator, auth_properties, environment, config_from_environment);
141         }
142     }
143     catch (ExitException) {
144         // Try again later
145         _configured = false;
146     }
147
148     if (Quassel::isOptionSet("select-backend") || Quassel::isOptionSet("select-authenticator")) {
149         bool success{true};
150         if (Quassel::isOptionSet("select-backend")) {
151             success &= selectBackend(Quassel::optionValue("select-backend"));
152         }
153         if (Quassel::isOptionSet("select-authenticator")) {
154             success &= selectAuthenticator(Quassel::optionValue("select-authenticator"));
155         }
156         throw ExitException{success ? EXIT_SUCCESS : EXIT_FAILURE};
157     }
158
159     if (!_configured) {
160         if (config_from_environment) {
161             try {
162                 _configured = initStorage(db_backend, db_connectionProperties, environment, config_from_environment, true);
163                 if (_configured) {
164                     _configured = initAuthenticator(auth_authenticator, auth_properties, environment, config_from_environment, true);
165                 }
166             }
167             catch (ExitException e) {
168                 throw ExitException{EXIT_FAILURE, tr("Cannot configure from environment: %1").arg(e.errorString)};
169             }
170
171             if (!_configured) {
172                 throw ExitException{EXIT_FAILURE, tr("Cannot configure from environment!")};
173             }
174         }
175         else {
176             if (_registeredStorageBackends.empty()) {
177                 throw ExitException{EXIT_FAILURE,
178                                     tr("Could not initialize any storage backend! Exiting...\n"
179                                        "Currently, Quassel supports SQLite3 and PostgreSQL. You need to build your\n"
180                                        "Qt library with the sqlite or postgres plugin enabled in order for quasselcore\n"
181                                        "to work.")};
182             }
183
184             if (writeError) {
185                 throw ExitException{EXIT_FAILURE, tr("Cannot write quasselcore configuration; probably a permission problem.")};
186             }
187
188             quInfo() << "Core is currently not configured! Please connect with a Quassel Client for basic setup.";
189         }
190     }
191     else {
192         if (Quassel::isOptionSet("add-user")) {
193             bool success = createUser();
194             throw ExitException{success ? EXIT_SUCCESS : EXIT_FAILURE};
195         }
196
197         if (Quassel::isOptionSet("change-userpass")) {
198             bool success = changeUserPass(Quassel::optionValue("change-userpass"));
199             throw ExitException{success ? EXIT_SUCCESS : EXIT_FAILURE};
200         }
201
202         _strictIdentEnabled = Quassel::isOptionSet("strict-ident");
203         if (_strictIdentEnabled) {
204             cacheSysIdent();
205         }
206
207         if (Quassel::isOptionSet("oidentd")) {
208             _oidentdConfigGenerator = new OidentdConfigGenerator(this);
209         }
210
211         if (Quassel::isOptionSet("ident-daemon")) {
212             _identServer = new IdentServer(this);
213         }
214
215         Quassel::registerReloadHandler([]() {
216             // Currently, only reloading SSL certificates and the sysident cache is supported
217             if (Core::instance()) {
218                 Core::instance()->cacheSysIdent();
219                 Core::instance()->reloadCerts();
220                 return true;
221             }
222             return false;
223         });
224
225         connect(&_storageSyncTimer, &QTimer::timeout, this, &Core::syncStorage);
226         _storageSyncTimer.start(10 * 60 * 1000);  // 10 minutes
227     }
228
229     connect(&_server, &QTcpServer::newConnection, this, &Core::incomingConnection);
230     connect(&_v6server, &QTcpServer::newConnection, this, &Core::incomingConnection);
231
232     if (!startListening()) {
233         throw ExitException{EXIT_FAILURE, tr("Cannot open port for listening!")};
234     }
235
236     if (_configured && !Quassel::isOptionSet("norestore")) {
237         Core::restoreState();
238     }
239
240     _initialized = true;
241
242     if (_pendingInternalConnection) {
243         connectInternalPeer(_pendingInternalConnection);
244         _pendingInternalConnection = {};
245     }
246 }
247
248 void Core::initAsync()
249 {
250     try {
251         init();
252     }
253     catch (ExitException e) {
254         emit exitRequested(e.exitCode, e.errorString);
255     }
256 }
257
258 void Core::shutdown()
259 {
260     quInfo() << "Core shutting down...";
261
262     saveState();
263
264     for (auto&& client : _connectingClients) {
265         client->deleteLater();
266     }
267     _connectingClients.clear();
268
269     if (_sessions.isEmpty()) {
270         emit shutdownComplete();
271         return;
272     }
273
274     for (auto&& session : _sessions) {
275         connect(session, &SessionThread::shutdownComplete, this, &Core::onSessionShutdown);
276         session->shutdown();
277     }
278 }
279
280 void Core::onSessionShutdown(SessionThread* session)
281 {
282     _sessions.take(_sessions.key(session))->deleteLater();
283     if (_sessions.isEmpty()) {
284         quInfo() << "Core shutdown complete!";
285         emit shutdownComplete();
286     }
287 }
288
289 /*** Session Restore ***/
290
291 void Core::saveState()
292 {
293     if (_storage) {
294         QVariantList activeSessions;
295         for (auto&& user : instance()->_sessions.keys())
296             activeSessions << QVariant::fromValue<UserId>(user);
297         _storage->setCoreState(activeSessions);
298     }
299 }
300
301 void Core::restoreState()
302 {
303     if (!_configured) {
304         quWarning() << qPrintable(tr("Cannot restore a state for an unconfigured core!"));
305         return;
306     }
307     if (_sessions.count()) {
308         quWarning() << qPrintable(tr("Calling restoreState() even though active sessions exist!"));
309         return;
310     }
311
312     CoreSettings s;
313     /* We don't check, since we are at the first version since switching to Git
314     uint statever = s.coreState().toMap()["CoreStateVersion"].toUInt();
315     if(statever < 1) {
316       quWarning() << qPrintable(tr("Core state too old, ignoring..."));
317       return;
318     }
319     */
320
321     const QList<QVariant>& activeSessionsFallback = s.coreState().toMap()["ActiveSessions"].toList();
322     QVariantList activeSessions = instance()->_storage->getCoreState(activeSessionsFallback);
323
324     if (activeSessions.count() > 0) {
325         quInfo() << "Restoring previous core state...";
326         for (auto&& v : activeSessions) {
327             UserId user = v.value<UserId>();
328             sessionForUser(user, true);
329         }
330     }
331 }
332
333 /*** Core Setup ***/
334
335 QString Core::setup(const QString& adminUser,
336                     const QString& adminPassword,
337                     const QString& backend,
338                     const QVariantMap& setupData,
339                     const QString& authenticator,
340                     const QVariantMap& authSetupData)
341 {
342     return instance()->setupCore(adminUser, adminPassword, backend, setupData, authenticator, authSetupData);
343 }
344
345 QString Core::setupCore(const QString& adminUser,
346                         const QString& adminPassword,
347                         const QString& backend,
348                         const QVariantMap& setupData,
349                         const QString& authenticator,
350                         const QVariantMap& authSetupData)
351 {
352     if (_configured)
353         return tr("Core is already configured! Not configuring again...");
354
355     if (adminUser.isEmpty() || adminPassword.isEmpty()) {
356         return tr("Admin user or password not set.");
357     }
358     try {
359         if (!(_configured = initStorage(backend, setupData, {}, false, true))) {
360             return tr("Could not setup storage!");
361         }
362
363         quInfo() << "Selected authenticator:" << authenticator;
364         if (!(_configured = initAuthenticator(authenticator, authSetupData, {}, false, true))) {
365             return tr("Could not setup authenticator!");
366         }
367     }
368     catch (ExitException e) {
369         // Event loop is running, so trigger an exit rather than throwing an exception
370         QCoreApplication::exit(e.exitCode);
371         return e.errorString.isEmpty() ? tr("Fatal failure while trying to setup, terminating") : e.errorString;
372     }
373
374     if (!saveBackendSettings(backend, setupData)) {
375         return tr("Could not save backend settings, probably a permission problem.");
376     }
377     saveAuthenticatorSettings(authenticator, authSetupData);
378
379     quInfo() << qPrintable(tr("Creating admin user..."));
380     _storage->addUser(adminUser, adminPassword);
381     cacheSysIdent();
382     startListening();  // TODO check when we need this
383     return QString();
384 }
385
386 QString Core::setupCoreForInternalUsage()
387 {
388     Q_ASSERT(!_registeredStorageBackends.empty());
389
390     qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch());
391     int pass = 0;
392     for (int i = 0; i < 10; i++) {
393         pass *= 10;
394         pass += qrand() % 10;
395     }
396
397     // mono client currently needs sqlite
398     return setupCore("AdminUser", QString::number(pass), "SQLite", QVariantMap(), "Database", QVariantMap());
399 }
400
401 /*** Storage Handling ***/
402
403 template<typename Storage>
404 void Core::registerStorageBackend()
405 {
406     auto backend = makeDeferredShared<Storage>(this);
407     if (backend->isAvailable())
408         _registeredStorageBackends.emplace_back(std::move(backend));
409     else
410         backend->deleteLater();
411 }
412
413 void Core::registerStorageBackends()
414 {
415     if (_registeredStorageBackends.empty()) {
416         registerStorageBackend<SqliteStorage>();
417         registerStorageBackend<PostgreSqlStorage>();
418     }
419 }
420
421 DeferredSharedPtr<Storage> Core::storageBackend(const QString& backendId) const
422 {
423     auto it = std::find_if(_registeredStorageBackends.begin(),
424                            _registeredStorageBackends.end(),
425                            [backendId](const DeferredSharedPtr<Storage>& backend) { return backend->displayName() == backendId; });
426     return it != _registeredStorageBackends.end() ? *it : nullptr;
427 }
428
429 bool Core::initStorage(
430     const QString& backend, const QVariantMap& settings, const QProcessEnvironment& environment, bool loadFromEnvironment, bool setup)
431 {
432     if (backend.isEmpty()) {
433         quWarning() << "No storage backend selected!";
434         return false;
435     }
436
437     auto storage = storageBackend(backend);
438     if (!storage) {
439         qCritical() << "Selected storage backend is not available:" << backend;
440         return false;
441     }
442
443     connect(storage.get(), &Storage::dbUpgradeInProgress, this, &Core::dbUpgradeInProgress);
444
445     Storage::State storageState = storage->init(settings, environment, loadFromEnvironment);
446     switch (storageState) {
447     case Storage::NeedsSetup:
448         if (!setup)
449             return false;  // trigger setup process
450         if (storage->setup(settings, environment, loadFromEnvironment))
451             return initStorage(backend, settings, environment, loadFromEnvironment, false);
452         return false;
453
454     case Storage::NotAvailable:
455         if (!setup) {
456             // If initialization wasn't successful, we quit to keep from coming up unconfigured
457             throw ExitException{EXIT_FAILURE, tr("Selected storage backend %1 is not available.").arg(backend)};
458         }
459         qCritical() << "Selected storage backend is not available:" << backend;
460         return false;
461
462     case Storage::IsReady:
463         // delete all other backends
464         _registeredStorageBackends.clear();
465         connect(storage.get(), &Storage::bufferInfoUpdated, this, &Core::bufferInfoUpdated);
466         break;
467     }
468     _storage = std::move(storage);
469     return true;
470 }
471
472 void Core::syncStorage()
473 {
474     if (_storage)
475         _storage->sync();
476 }
477
478 /*** Storage Access ***/
479 bool Core::createNetwork(UserId user, NetworkInfo& info)
480 {
481     NetworkId networkId = instance()->_storage->createNetwork(user, info);
482     if (!networkId.isValid())
483         return false;
484
485     info.networkId = networkId;
486     return true;
487 }
488
489 /*** Authenticators ***/
490
491 // Authentication handling, now independent from storage.
492 template<typename Authenticator>
493 void Core::registerAuthenticator()
494 {
495     auto authenticator = makeDeferredShared<Authenticator>(this);
496     if (authenticator->isAvailable())
497         _registeredAuthenticators.emplace_back(std::move(authenticator));
498     else
499         authenticator->deleteLater();
500 }
501
502 void Core::registerAuthenticators()
503 {
504     if (_registeredAuthenticators.empty()) {
505         registerAuthenticator<SqlAuthenticator>();
506 #ifdef HAVE_LDAP
507         registerAuthenticator<LdapAuthenticator>();
508 #endif
509     }
510 }
511
512 DeferredSharedPtr<Authenticator> Core::authenticator(const QString& backendId) const
513 {
514     auto it = std::find_if(_registeredAuthenticators.begin(),
515                            _registeredAuthenticators.end(),
516                            [backendId](const DeferredSharedPtr<Authenticator>& authenticator) {
517                                return authenticator->backendId() == backendId;
518                            });
519     return it != _registeredAuthenticators.end() ? *it : nullptr;
520 }
521
522 // FIXME: Apparently, this is the legacy way of initting storage backends?
523 // If there's a not-legacy way, it should be used here
524 bool Core::initAuthenticator(
525     const QString& backend, const QVariantMap& settings, const QProcessEnvironment& environment, bool loadFromEnvironment, bool setup)
526 {
527     if (backend.isEmpty()) {
528         quWarning() << "No authenticator selected!";
529         return false;
530     }
531
532     auto auth = authenticator(backend);
533     if (!auth) {
534         qCritical() << "Selected auth backend is not available:" << backend;
535         return false;
536     }
537
538     Authenticator::State authState = auth->init(settings, environment, loadFromEnvironment);
539     switch (authState) {
540     case Authenticator::NeedsSetup:
541         if (!setup)
542             return false;  // trigger setup process
543         if (auth->setup(settings, environment, loadFromEnvironment))
544             return initAuthenticator(backend, settings, environment, loadFromEnvironment, false);
545         return false;
546
547     case Authenticator::NotAvailable:
548         if (!setup) {
549             // If initialization wasn't successful, we quit to keep from coming up unconfigured
550             throw ExitException{EXIT_FAILURE, tr("Selected auth backend %1 is not available.").arg(backend)};
551         }
552         qCritical() << "Selected auth backend is not available:" << backend;
553         return false;
554
555     case Authenticator::IsReady:
556         // delete all other backends
557         _registeredAuthenticators.clear();
558         break;
559     }
560     _authenticator = std::move(auth);
561     return true;
562 }
563
564 /*** Network Management ***/
565
566 bool Core::sslSupported()
567 {
568 #ifdef HAVE_SSL
569     auto* sslServer = qobject_cast<SslServer*>(&instance()->_server);
570     return sslServer && sslServer->isCertValid();
571 #else
572     return false;
573 #endif
574 }
575
576 bool Core::reloadCerts()
577 {
578 #ifdef HAVE_SSL
579     auto* sslServerv4 = qobject_cast<SslServer*>(&_server);
580     bool retv4 = sslServerv4->reloadCerts();
581
582     auto* sslServerv6 = qobject_cast<SslServer*>(&_v6server);
583     bool retv6 = sslServerv6->reloadCerts();
584
585     return retv4 && retv6;
586 #else
587     // SSL not supported, don't mark configuration reload as failed
588     return true;
589 #endif
590 }
591
592 void Core::cacheSysIdent()
593 {
594     if (isConfigured()) {
595         _authUserNames = _storage->getAllAuthUserNames();
596     }
597 }
598
599 QString Core::strictSysIdent(UserId user) const
600 {
601     if (_authUserNames.contains(user)) {
602         return _authUserNames[user];
603     }
604
605     // A new user got added since we last pulled our cache from the database.
606     // There's no way to avoid a database hit - we don't even know the authname!
607     instance()->cacheSysIdent();
608
609     if (_authUserNames.contains(user)) {
610         return _authUserNames[user];
611     }
612
613     // ...something very weird is going on if we ended up here (an active CoreSession without a corresponding database entry?)
614     qWarning().nospace() << "Unable to find authusername for UserId " << user << ", this should never happen!";
615     return "unknown";  // Should we just terminate the program instead?
616 }
617
618 bool Core::startListening()
619 {
620     // in mono mode we only start a local port if a port is specified in the cli call
621     if (Quassel::runMode() == Quassel::Monolithic && !Quassel::isOptionSet("port"))
622         return true;
623
624     bool success = false;
625     uint port = Quassel::optionValue("port").toUInt();
626
627     const QString listen = Quassel::optionValue("listen");
628     const QStringList listen_list = listen.split(",", QString::SkipEmptyParts);
629     if (listen_list.size() > 0) {
630         foreach (const QString listen_term, listen_list) {  // TODO: handle multiple interfaces for same TCP version gracefully
631             QHostAddress addr;
632             if (!addr.setAddress(listen_term)) {
633                 qCritical() << qPrintable(tr("Invalid listen address %1").arg(listen_term));
634             }
635             else {
636                 switch (addr.protocol()) {
637                 case QAbstractSocket::IPv6Protocol:
638                     if (_v6server.listen(addr, port)) {
639                         quInfo() << qPrintable(tr("Listening for GUI clients on IPv6 %1 port %2 using protocol version %3")
640                                                    .arg(addr.toString())
641                                                    .arg(_v6server.serverPort())
642                                                    .arg(Quassel::buildInfo().protocolVersion));
643                         success = true;
644                     }
645                     else
646                         quWarning() << qPrintable(
647                             tr("Could not open IPv6 interface %1:%2: %3").arg(addr.toString()).arg(port).arg(_v6server.errorString()));
648                     break;
649                 case QAbstractSocket::IPv4Protocol:
650                     if (_server.listen(addr, port)) {
651                         quInfo() << qPrintable(tr("Listening for GUI clients on IPv4 %1 port %2 using protocol version %3")
652                                                    .arg(addr.toString())
653                                                    .arg(_server.serverPort())
654                                                    .arg(Quassel::buildInfo().protocolVersion));
655                         success = true;
656                     }
657                     else {
658                         // if v6 succeeded on Any, the port will be already in use - don't display the error then
659                         if (!success || _server.serverError() != QAbstractSocket::AddressInUseError)
660                             quWarning() << qPrintable(
661                                 tr("Could not open IPv4 interface %1:%2: %3").arg(addr.toString()).arg(port).arg(_server.errorString()));
662                     }
663                     break;
664                 default:
665                     qCritical() << qPrintable(tr("Invalid listen address %1, unknown network protocol").arg(listen_term));
666                     break;
667                 }
668             }
669         }
670     }
671     if (!success)
672         quError() << qPrintable(tr("Could not open any network interfaces to listen on!"));
673
674     if (_identServer) {
675         _identServer->startListening();
676     }
677
678     return success;
679 }
680
681 void Core::stopListening(const QString& reason)
682 {
683     if (_identServer) {
684         _identServer->stopListening(reason);
685     }
686
687     bool wasListening = false;
688     if (_server.isListening()) {
689         wasListening = true;
690         _server.close();
691     }
692     if (_v6server.isListening()) {
693         wasListening = true;
694         _v6server.close();
695     }
696     if (wasListening) {
697         if (reason.isEmpty())
698             quInfo() << "No longer listening for GUI clients.";
699         else
700             quInfo() << qPrintable(reason);
701     }
702 }
703
704 void Core::incomingConnection()
705 {
706     auto* server = qobject_cast<QTcpServer*>(sender());
707     Q_ASSERT(server);
708     while (server->hasPendingConnections()) {
709         QTcpSocket* socket = server->nextPendingConnection();
710
711         auto* handler = new CoreAuthHandler(socket, this);
712         _connectingClients.insert(handler);
713
714         connect(handler, &AuthHandler::disconnected, this, &Core::clientDisconnected);
715         connect(handler, &AuthHandler::socketError, this, &Core::socketError);
716         connect(handler, &CoreAuthHandler::handshakeComplete, this, &Core::setupClientSession);
717
718         quInfo() << qPrintable(tr("Client connected from")) << qPrintable(socket->peerAddress().toString());
719
720         if (!_configured) {
721             stopListening(tr("Closing server for basic setup."));
722         }
723     }
724 }
725
726 // Potentially called during the initialization phase (before handing the connection off to the session)
727 void Core::clientDisconnected()
728 {
729     auto* handler = qobject_cast<CoreAuthHandler*>(sender());
730     Q_ASSERT(handler);
731
732     quInfo() << qPrintable(tr("Non-authed client disconnected:")) << qPrintable(handler->socket()->peerAddress().toString());
733     _connectingClients.remove(handler);
734     handler->deleteLater();
735
736     // make server listen again if still not configured
737     if (!_configured) {
738         startListening();
739     }
740
741     // TODO remove unneeded sessions - if necessary/possible...
742     // Suggestion: kill sessions if they are not connected to any network and client.
743 }
744
745 void Core::setupClientSession(RemotePeer* peer, UserId uid)
746 {
747     auto* handler = qobject_cast<CoreAuthHandler*>(sender());
748     Q_ASSERT(handler);
749
750     // From now on everything is handled by the client session
751     disconnect(handler, nullptr, this, nullptr);
752     _connectingClients.remove(handler);
753     handler->deleteLater();
754
755     // Find or create session for validated user
756     sessionForUser(uid);
757
758     // as we are currently handling an event triggered by incoming data on this socket
759     // it is unsafe to directly move the socket to the client thread.
760     QCoreApplication::postEvent(this, new AddClientEvent(peer, uid));
761 }
762
763 void Core::customEvent(QEvent* event)
764 {
765     if (event->type() == AddClientEventId) {
766         auto* addClientEvent = static_cast<AddClientEvent*>(event);
767         addClientHelper(addClientEvent->peer, addClientEvent->userId);
768         return;
769     }
770 }
771
772 void Core::addClientHelper(RemotePeer* peer, UserId uid)
773 {
774     // Find or create session for validated user
775     SessionThread* session = sessionForUser(uid);
776     session->addClient(peer);
777 }
778
779 void Core::connectInternalPeer(QPointer<InternalPeer> peer)
780 {
781     if (_initialized && peer) {
782         setupInternalClientSession(peer);
783     }
784     else {
785         _pendingInternalConnection = peer;
786     }
787 }
788
789 void Core::setupInternalClientSession(QPointer<InternalPeer> clientPeer)
790 {
791     if (!_configured) {
792         stopListening();
793         auto errorString = setupCoreForInternalUsage();
794         if (!errorString.isEmpty()) {
795             emit exitRequested(EXIT_FAILURE, errorString);
796             return;
797         }
798     }
799
800     UserId uid;
801     if (_storage) {
802         uid = _storage->internalUser();
803     }
804     else {
805         quWarning() << "Core::setupInternalClientSession(): You're trying to run monolithic Quassel with an unusable Backend! Go fix it!";
806         emit exitRequested(EXIT_FAILURE, tr("Cannot setup storage backend."));
807         return;
808     }
809
810     if (!clientPeer) {
811         quWarning() << "Client peer went away, not starting a session";
812         return;
813     }
814
815     auto* corePeer = new InternalPeer(this);
816     corePeer->setPeer(clientPeer);
817     clientPeer->setPeer(corePeer);
818
819     // Find or create session for validated user
820     SessionThread* sessionThread = sessionForUser(uid);
821     sessionThread->addClient(corePeer);
822 }
823
824 SessionThread* Core::sessionForUser(UserId uid, bool restore)
825 {
826     if (_sessions.contains(uid))
827         return _sessions[uid];
828
829     return (_sessions[uid] = new SessionThread(uid, restore, strictIdentEnabled(), this));
830 }
831
832 void Core::socketError(QAbstractSocket::SocketError err, const QString& errorString)
833 {
834     quWarning() << QString("Socket error %1: %2").arg(err).arg(errorString);
835 }
836
837 QVariantList Core::backendInfo()
838 {
839     instance()->registerStorageBackends();
840
841     QVariantList backendInfos;
842     for (auto&& backend : instance()->_registeredStorageBackends) {
843         QVariantMap v;
844         v["BackendId"] = backend->backendId();
845         v["DisplayName"] = backend->displayName();
846         v["Description"] = backend->description();
847         v["SetupData"] = backend->setupData();  // ignored by legacy clients
848
849         // TODO Protocol Break: Remove legacy (cf. authenticatorInfo())
850         const auto& setupData = backend->setupData();
851         QStringList setupKeys;
852         QVariantMap setupDefaults;
853         for (int i = 0; i + 2 < setupData.size(); i += 3) {
854             setupKeys << setupData[i].toString();
855             setupDefaults[setupData[i].toString()] = setupData[i + 2];
856         }
857         v["SetupKeys"] = setupKeys;
858         v["SetupDefaults"] = setupDefaults;
859         // TODO Protocol Break: Remove
860         v["IsDefault"] = (backend->backendId() == "SQLite");  // newer clients will just use the first in the list
861
862         backendInfos << v;
863     }
864     return backendInfos;
865 }
866
867 QVariantList Core::authenticatorInfo()
868 {
869     instance()->registerAuthenticators();
870
871     QVariantList authInfos;
872     for (auto&& backend : instance()->_registeredAuthenticators) {
873         QVariantMap v;
874         v["BackendId"] = backend->backendId();
875         v["DisplayName"] = backend->displayName();
876         v["Description"] = backend->description();
877         v["SetupData"] = backend->setupData();
878         authInfos << v;
879     }
880     return authInfos;
881 }
882
883 // migration / backend selection
884 bool Core::selectBackend(const QString& backend)
885 {
886     // reregister all storage backends
887     registerStorageBackends();
888     auto storage = storageBackend(backend);
889     if (!storage) {
890         QStringList backends;
891         std::transform(_registeredStorageBackends.begin(),
892                        _registeredStorageBackends.end(),
893                        std::back_inserter(backends),
894                        [](const DeferredSharedPtr<Storage>& backend) { return backend->displayName(); });
895         quWarning() << qPrintable(tr("Unsupported storage backend: %1").arg(backend));
896         quWarning() << qPrintable(tr("Supported backends are:")) << qPrintable(backends.join(", "));
897         return false;
898     }
899
900     QVariantMap settings = promptForSettings(storage.get());
901
902     Storage::State storageState = storage->init(settings);
903     switch (storageState) {
904     case Storage::IsReady:
905         if (!saveBackendSettings(backend, settings)) {
906             qCritical() << qPrintable(QString("Could not save backend settings, probably a permission problem."));
907         }
908         quWarning() << qPrintable(tr("Switched storage backend to: %1").arg(backend));
909         quWarning() << qPrintable(tr("Backend already initialized. Skipping Migration..."));
910         return true;
911     case Storage::NotAvailable:
912         qCritical() << qPrintable(tr("Storage backend is not available: %1").arg(backend));
913         return false;
914     case Storage::NeedsSetup:
915         if (!storage->setup(settings)) {
916             quWarning() << qPrintable(tr("Unable to setup storage backend: %1").arg(backend));
917             return false;
918         }
919
920         if (storage->init(settings) != Storage::IsReady) {
921             quWarning() << qPrintable(tr("Unable to initialize storage backend: %1").arg(backend));
922             return false;
923         }
924
925         if (!saveBackendSettings(backend, settings)) {
926             qCritical() << qPrintable(QString("Could not save backend settings, probably a permission problem."));
927         }
928         quWarning() << qPrintable(tr("Switched storage backend to: %1").arg(backend));
929         break;
930     }
931
932     // let's see if we have a current storage object we can migrate from
933     auto reader = getMigrationReader(_storage.get());
934     auto writer = getMigrationWriter(storage.get());
935     if (reader && writer) {
936         qDebug() << qPrintable(tr("Migrating storage backend %1 to %2...").arg(_storage->displayName(), storage->displayName()));
937         _storage.reset();
938         storage.reset();
939         if (reader->migrateTo(writer.get())) {
940             qDebug() << "Migration finished!";
941             qDebug() << qPrintable(tr("Migration finished!"));
942             if (!saveBackendSettings(backend, settings)) {
943                 qCritical() << qPrintable(QString("Could not save backend settings, probably a permission problem."));
944                 return false;
945             }
946             return true;
947         }
948         quWarning() << qPrintable(tr("Unable to migrate storage backend! (No migration writer for %1)").arg(backend));
949         return false;
950     }
951
952     // inform the user why we cannot merge
953     if (!_storage) {
954         quWarning() << qPrintable(tr("No currently active storage backend. Skipping migration..."));
955     }
956     else if (!reader) {
957         quWarning() << qPrintable(tr("Currently active storage backend does not support migration: %1").arg(_storage->displayName()));
958     }
959     if (writer) {
960         quWarning() << qPrintable(tr("New storage backend does not support migration: %1").arg(backend));
961     }
962
963     // so we were unable to merge, but let's create a user \o/
964     _storage = std::move(storage);
965     createUser();
966     return true;
967 }
968
969 // TODO: I am not sure if this function is implemented correctly.
970 // There is currently no concept of migraiton between auth backends.
971 bool Core::selectAuthenticator(const QString& backend)
972 {
973     // Register all authentication backends.
974     registerAuthenticators();
975     auto auther = authenticator(backend);
976     if (!auther) {
977         QStringList authenticators;
978         std::transform(_registeredAuthenticators.begin(),
979                        _registeredAuthenticators.end(),
980                        std::back_inserter(authenticators),
981                        [](const DeferredSharedPtr<Authenticator>& authenticator) { return authenticator->displayName(); });
982         quWarning() << qPrintable(tr("Unsupported authenticator: %1").arg(backend));
983         quWarning() << qPrintable(tr("Supported authenticators are:")) << qPrintable(authenticators.join(", "));
984         return false;
985     }
986
987     QVariantMap settings = promptForSettings(auther.get());
988
989     Authenticator::State state = auther->init(settings);
990     switch (state) {
991     case Authenticator::IsReady:
992         saveAuthenticatorSettings(backend, settings);
993         quWarning() << qPrintable(tr("Switched authenticator to: %1").arg(backend));
994         return true;
995     case Authenticator::NotAvailable:
996         qCritical() << qPrintable(tr("Authenticator is not available: %1").arg(backend));
997         return false;
998     case Authenticator::NeedsSetup:
999         if (!auther->setup(settings)) {
1000             quWarning() << qPrintable(tr("Unable to setup authenticator: %1").arg(backend));
1001             return false;
1002         }
1003
1004         if (auther->init(settings) != Authenticator::IsReady) {
1005             quWarning() << qPrintable(tr("Unable to initialize authenticator: %1").arg(backend));
1006             return false;
1007         }
1008
1009         saveAuthenticatorSettings(backend, settings);
1010         quWarning() << qPrintable(tr("Switched authenticator to: %1").arg(backend));
1011     }
1012
1013     _authenticator = std::move(auther);
1014     return true;
1015 }
1016
1017 bool Core::createUser()
1018 {
1019     QTextStream out(stdout);
1020     QTextStream in(stdin);
1021     out << "Add a new user:" << endl;
1022     out << "Username: ";
1023     out.flush();
1024     QString username = in.readLine().trimmed();
1025
1026     disableStdInEcho();
1027     out << "Password: ";
1028     out.flush();
1029     QString password = in.readLine().trimmed();
1030     out << endl;
1031     out << "Repeat Password: ";
1032     out.flush();
1033     QString password2 = in.readLine().trimmed();
1034     out << endl;
1035     enableStdInEcho();
1036
1037     if (password != password2) {
1038         quWarning() << "Passwords don't match!";
1039         return false;
1040     }
1041     if (password.isEmpty()) {
1042         quWarning() << "Password is empty!";
1043         return false;
1044     }
1045
1046     if (_configured && _storage->addUser(username, password).isValid()) {
1047         out << "Added user " << username << " successfully!" << endl;
1048         return true;
1049     }
1050     else {
1051         quWarning() << "Unable to add user:" << qPrintable(username);
1052         return false;
1053     }
1054 }
1055
1056 bool Core::changeUserPass(const QString& username)
1057 {
1058     QTextStream out(stdout);
1059     QTextStream in(stdin);
1060     UserId userId = _storage->getUserId(username);
1061     if (!userId.isValid()) {
1062         out << "User " << username << " does not exist." << endl;
1063         return false;
1064     }
1065
1066     if (!canChangeUserPassword(userId)) {
1067         out << "User " << username << " is configured through an auth provider that has forbidden manual password changing." << endl;
1068         return false;
1069     }
1070
1071     out << "Change password for user: " << username << endl;
1072
1073     disableStdInEcho();
1074     out << "New Password: ";
1075     out.flush();
1076     QString password = in.readLine().trimmed();
1077     out << endl;
1078     out << "Repeat Password: ";
1079     out.flush();
1080     QString password2 = in.readLine().trimmed();
1081     out << endl;
1082     enableStdInEcho();
1083
1084     if (password != password2) {
1085         quWarning() << "Passwords don't match!";
1086         return false;
1087     }
1088     if (password.isEmpty()) {
1089         quWarning() << "Password is empty!";
1090         return false;
1091     }
1092
1093     if (_configured && _storage->updateUser(userId, password)) {
1094         out << "Password changed successfully!" << endl;
1095         return true;
1096     }
1097     else {
1098         quWarning() << "Failed to change password!";
1099         return false;
1100     }
1101 }
1102
1103 bool Core::changeUserPassword(UserId userId, const QString& password)
1104 {
1105     if (!isConfigured() || !userId.isValid())
1106         return false;
1107
1108     if (!canChangeUserPassword(userId))
1109         return false;
1110
1111     return instance()->_storage->updateUser(userId, password);
1112 }
1113
1114 // TODO: this code isn't currently 100% optimal because the core
1115 // doesn't know it can have multiple auth providers configured (there aren't
1116 // multiple auth providers at the moment anyway) and we have hardcoded the
1117 // Database provider to be always allowed.
1118 bool Core::canChangeUserPassword(UserId userId)
1119 {
1120     QString authProvider = instance()->_storage->getUserAuthenticator(userId);
1121     if (authProvider != "Database") {
1122         if (authProvider != instance()->_authenticator->backendId()) {
1123             return false;
1124         }
1125         else if (instance()->_authenticator->canChangePassword()) {
1126             return false;
1127         }
1128     }
1129     return true;
1130 }
1131
1132 std::unique_ptr<AbstractSqlMigrationReader> Core::getMigrationReader(Storage* storage)
1133 {
1134     if (!storage)
1135         return nullptr;
1136
1137     auto* sqlStorage = qobject_cast<AbstractSqlStorage*>(storage);
1138     if (!sqlStorage) {
1139         qDebug() << "Core::migrateDb(): only SQL based backends can be migrated!";
1140         return nullptr;
1141     }
1142
1143     return sqlStorage->createMigrationReader();
1144 }
1145
1146 std::unique_ptr<AbstractSqlMigrationWriter> Core::getMigrationWriter(Storage* storage)
1147 {
1148     if (!storage)
1149         return nullptr;
1150
1151     auto* sqlStorage = qobject_cast<AbstractSqlStorage*>(storage);
1152     if (!sqlStorage) {
1153         qDebug() << "Core::migrateDb(): only SQL based backends can be migrated!";
1154         return nullptr;
1155     }
1156
1157     return sqlStorage->createMigrationWriter();
1158 }
1159
1160 bool Core::saveBackendSettings(const QString& backend, const QVariantMap& settings)
1161 {
1162     QVariantMap dbsettings;
1163     dbsettings["Backend"] = backend;
1164     dbsettings["ConnectionProperties"] = settings;
1165     CoreSettings s = CoreSettings();
1166     s.setStorageSettings(dbsettings);
1167     return s.sync();
1168 }
1169
1170 void Core::saveAuthenticatorSettings(const QString& backend, const QVariantMap& settings)
1171 {
1172     QVariantMap dbsettings;
1173     dbsettings["Authenticator"] = backend;
1174     dbsettings["AuthProperties"] = settings;
1175     CoreSettings().setAuthSettings(dbsettings);
1176 }
1177
1178 // Generic version of promptForSettings that doesn't care what *type* of
1179 // backend it runs over.
1180 template<typename Backend>
1181 QVariantMap Core::promptForSettings(const Backend* backend)
1182 {
1183     QVariantMap settings;
1184     const QVariantList& setupData = backend->setupData();
1185
1186     if (setupData.isEmpty())
1187         return settings;
1188
1189     QTextStream out(stdout);
1190     QTextStream in(stdin);
1191     out << "Default values are in brackets" << endl;
1192
1193     for (int i = 0; i + 2 < setupData.size(); i += 3) {
1194         QString key = setupData[i].toString();
1195         out << setupData[i + 1].toString() << " [" << setupData[i + 2].toString() << "]: " << flush;
1196
1197         bool noEcho = key.toLower().contains("password");
1198         if (noEcho) {
1199             disableStdInEcho();
1200         }
1201         QString input = in.readLine().trimmed();
1202         if (noEcho) {
1203             out << endl;
1204             enableStdInEcho();
1205         }
1206
1207         QVariant value{setupData[i + 2]};
1208         if (!input.isEmpty()) {
1209             switch (value.type()) {
1210             case QVariant::Int:
1211                 value = input.toInt();
1212                 break;
1213             default:
1214                 value = input;
1215             }
1216         }
1217         settings[key] = value;
1218     }
1219     return settings;
1220 }
1221
1222 #ifdef Q_OS_WIN
1223 void Core::stdInEcho(bool on)
1224 {
1225     HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1226     DWORD mode = 0;
1227     GetConsoleMode(hStdin, &mode);
1228     if (on)
1229         mode |= ENABLE_ECHO_INPUT;
1230     else
1231         mode &= ~ENABLE_ECHO_INPUT;
1232     SetConsoleMode(hStdin, mode);
1233 }
1234
1235 #else
1236 void Core::stdInEcho(bool on)
1237 {
1238     termios t;
1239     tcgetattr(STDIN_FILENO, &t);
1240     if (on)
1241         t.c_lflag |= ECHO;
1242     else
1243         t.c_lflag &= ~ECHO;
1244     tcsetattr(STDIN_FILENO, TCSANOW, &t);
1245 }
1246
1247 #endif /* Q_OS_WIN */