X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fcore.cpp;h=04dd3bb2742af151db863b0489bba46aa60ef58f;hp=dfd2c95ae8c9e44985173306d7b5af4fe38bf0e6;hb=d9b17a008292b197247dca3b17814ab00dc0c586;hpb=8379f6f725cf8ed2fdad1a19bd10743436c2d086 diff --git a/src/core/core.cpp b/src/core/core.cpp index dfd2c95a..04dd3bb2 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2015 by the Quassel Project * + * Copyright (C) 2005-2016 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -29,9 +29,15 @@ #include "network.h" #include "postgresqlstorage.h" #include "quassel.h" +#include "sqlauthenticator.h" #include "sqlitestorage.h" #include "util.h" +// Currently building with LDAP bindings is optional. +#ifdef HAVE_LDAP +#include "ldapauthenticator.h" +#endif + // migration related #include #ifdef Q_OS_WIN @@ -83,7 +89,8 @@ void Core::destroy() Core::Core() : QObject(), - _storage(0) + _storage(0), + _authenticator(0) { #ifdef HAVE_UMASK umask(S_IRWXG | S_IRWXO); @@ -168,6 +175,7 @@ Core::Core() } registerStorageBackends(); + registerAuthenticatorBackends(); connect(&_storageSyncTimer, SIGNAL(timeout()), this, SLOT(syncStorage())); _storageSyncTimer.start(10 * 60 * 1000); // 10 minutes @@ -181,11 +189,17 @@ void Core::init() QVariantMap dbsettings = cs.storageSettings().toMap(); _configured = initStorage(dbsettings.value("Backend").toString(), dbsettings.value("ConnectionProperties").toMap()); + // Not entirely sure what is 'legacy' about the above, but it seems to be the way things work! + QVariantMap authSettings = cs.authSettings().toMap(); + initAuthenticator(authSettings.value("AuthBackend").toString(), authSettings.value("ConnectionProperties").toMap()); + if (Quassel::isOptionSet("select-backend")) { selectBackend(Quassel::optionValue("select-backend")); exit(0); } + // TODO: add --select-authenticator command line option and code. + if (!_configured) { if (!_storageBackends.count()) { qWarning() << qPrintable(tr("Could not initialize any storage backend! Exiting...")); @@ -194,17 +208,24 @@ void Core::init() "to work.")); exit(1); // TODO make this less brutal (especially for mono client -> popup) } + qWarning() << "Core is currently not configured! Please connect with a Quassel Client for basic setup."; + + if (!cs.isWritable()) { + qWarning() << "Cannot write quasselcore configuration; probably a permission problem."; + exit(EXIT_FAILURE); + } + } if (Quassel::isOptionSet("add-user")) { - createUser(); - exit(0); + exit(createUser() ? EXIT_SUCCESS : EXIT_FAILURE); + } if (Quassel::isOptionSet("change-userpass")) { - changeUserPass(Quassel::optionValue("change-userpass")); - exit(0); + exit(changeUserPass(Quassel::optionValue("change-userpass")) ? + EXIT_SUCCESS : EXIT_FAILURE); } connect(&_server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); @@ -224,6 +245,7 @@ Core::~Core() } qDeleteAll(_sessions); qDeleteAll(_storageBackends); + qDeleteAll(_authenticatorBackends); } @@ -274,13 +296,13 @@ void Core::restoreState() /*** Core Setup ***/ -QString Core::setup(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData) +QString Core::setup(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData, const QString &authBackend, const QVariantMap &authSetupData) { - return instance()->setupCore(adminUser, adminPassword, backend, setupData); + return instance()->setupCore(adminUser, adminPassword, backend, setupData, authBackend, authSetupData); } -QString Core::setupCore(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData) +QString Core::setupCore(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData, const QString &authBackend, const QVariantMap &authSetupData) { if (_configured) return tr("Core is already configured! Not configuring again..."); @@ -292,7 +314,16 @@ QString Core::setupCore(const QString &adminUser, const QString &adminPassword, return tr("Could not setup storage!"); } - saveBackendSettings(backend, setupData); + quInfo() << "Selected authenticator: " << authBackend; + if (!(_configured = initAuthenticator(authBackend, authSetupData, true))) + { + return tr("Could not setup authenticator!"); + } + + if (!saveBackendSettings(backend, setupData)) { + return tr("Could not save backend settings, probably a permission problem."); + } + saveAuthBackendSettings(authBackend, authSetupData); quInfo() << qPrintable(tr("Creating admin user...")); _storage->addUser(adminUser, adminPassword); @@ -313,7 +344,7 @@ QString Core::setupCoreForInternalUsage() } // mono client currently needs sqlite - return setupCore("AdminUser", QString::number(pass), "SQLite", QVariantMap()); + return setupCore("AdminUser", QString::number(pass), "SQLite", QVariantMap(), "StorageAuth", QVariantMap()); } @@ -338,7 +369,6 @@ bool Core::registerStorageBackend(Storage *backend) } } - void Core::unregisterStorageBackends() { foreach(Storage *s, _storageBackends.values()) { @@ -354,6 +384,45 @@ void Core::unregisterStorageBackend(Storage *backend) backend->deleteLater(); } +// Authentication handling, now independent from storage. +// Register and unregister authenticators. + +void Core::registerAuthenticatorBackends() +{ + // Register new authentication backends here! + registerAuthenticatorBackend(new SqlAuthenticator(this)); +#ifdef HAVE_LDAP + registerAuthenticatorBackend(new LdapAuthenticator(this)); +#endif + +} + +bool Core::registerAuthenticatorBackend(Authenticator *authenticator) +{ + if (authenticator->isAvailable()) + { + _authenticatorBackends[authenticator->displayName()] = authenticator; + return true; + } else { + authenticator->deleteLater(); + return false; + } +} + +void Core::unregisterAuthenticatorBackends() +{ + foreach(Authenticator* a, _authenticatorBackends.values()) + { + a->deleteLater(); + } + _authenticatorBackends.clear(); +} + +void Core::unregisterAuthenticatorBackend(Authenticator *backend) +{ + _authenticatorBackends.remove(backend->displayName()); + backend->deleteLater(); +} // old db settings: // "Type" => "sqlite" @@ -395,6 +464,43 @@ bool Core::initStorage(const QString &backend, const QVariantMap &settings, bool return true; } +// XXX: TODO: Apparently, this is legacy? +bool Core::initAuthenticator(const QString &backend, const QVariantMap &settings, bool setup) +{ + _authenticator = 0; + + if (backend.isEmpty()) { + return false; + } + + Authenticator *authenticator = 0; + if (_authenticatorBackends.contains(backend)) { + authenticator = _authenticatorBackends[backend]; + } + else { + qCritical() << "Selected auth backend is not available:" << backend; + return false; + } + + Authenticator::State authState = authenticator->init(settings); + switch (authState) { + case Authenticator::NeedsSetup: + if (!setup) + return false; // trigger setup process + if (authenticator->setup(settings)) + return initAuthenticator(backend, settings, false); + // if initialization wasn't successful, we quit to keep from coming up unconfigured + case Authenticator::NotAvailable: + qCritical() << "FATAL: Selected auth backend is not available:" << backend; + exit(EXIT_FAILURE); + case Authenticator::IsReady: + // delete all other backends + _authenticatorBackends.remove(backend); + unregisterAuthenticatorBackends(); + } + _authenticator = authenticator; + return true; +} void Core::syncStorage() { @@ -428,6 +534,23 @@ bool Core::sslSupported() } +bool Core::reloadCerts() +{ +#ifdef HAVE_SSL + SslServer *sslServerv4 = qobject_cast(&instance()->_server); + bool retv4 = sslServerv4->reloadCerts(); + + SslServer *sslServerv6 = qobject_cast(&instance()->_v6server); + bool retv6 = sslServerv6->reloadCerts(); + + return retv4 && retv6; +#else + // SSL not supported, don't mark configuration reload as failed + return true; +#endif +} + + bool Core::startListening() { // in mono mode we only start a local port if a port is specified in the cli call @@ -638,7 +761,6 @@ SessionThread *Core::sessionForUser(UserId uid, bool restore) SessionThread *session = new SessionThread(uid, restore, this); _sessions[uid] = session; session->start(); - connect(session, SIGNAL(passwordChangeRequested(UserId, QString)), _storage, SLOT(updateUser(UserId, QString))); return session; } @@ -658,11 +780,25 @@ QVariantList Core::backendInfo() v["Description"] = backend->description(); v["SetupKeys"] = backend->setupKeys(); v["SetupDefaults"] = backend->setupDefaults(); + v["IsDefault"] = isStorageBackendDefault(backend); backends.append(v); } return backends; } +QVariantList Core::authenticatorInfo() +{ + QVariantList backends; + foreach(const Authenticator *backend, instance()->_authenticatorBackends.values()) { + QVariantMap v; + v["DisplayName"] = backend->displayName(); + v["Description"] = backend->description(); + v["SetupKeys"] = backend->setupKeys(); + v["SetupDefaults"] = backend->setupDefaults(); + backends.append(v); + } + return backends; +} // migration / backend selection bool Core::selectBackend(const QString &backend) @@ -681,7 +817,9 @@ bool Core::selectBackend(const QString &backend) Storage::State storageState = storage->init(settings); switch (storageState) { case Storage::IsReady: - saveBackendSettings(backend, settings); + if (!saveBackendSettings(backend, settings)) { + qCritical() << qPrintable(QString("Could not save backend settings, probably a permission problem.")); + } qWarning() << "Switched backend to:" << qPrintable(backend); qWarning() << "Backend already initialized. Skipping Migration"; return true; @@ -699,7 +837,9 @@ bool Core::selectBackend(const QString &backend) return false; } - saveBackendSettings(backend, settings); + if (!saveBackendSettings(backend, settings)) { + qCritical() << qPrintable(QString("Could not save backend settings, probably a permission problem.")); + } qWarning() << "Switched backend to:" << qPrintable(backend); break; } @@ -715,7 +855,10 @@ bool Core::selectBackend(const QString &backend) storage = 0; if (reader->migrateTo(writer)) { qDebug() << "Migration finished!"; - saveBackendSettings(backend, settings); + if (!saveBackendSettings(backend, settings)) { + qCritical() << qPrintable(QString("Could not save backend settings, probably a permission problem.")); + return false; + } return true; } return false; @@ -740,7 +883,7 @@ bool Core::selectBackend(const QString &backend) } -void Core::createUser() +bool Core::createUser() { QTextStream out(stdout); QTextStream in(stdin); @@ -762,30 +905,32 @@ void Core::createUser() if (password != password2) { qWarning() << "Passwords don't match!"; - return; + return false; } if (password.isEmpty()) { qWarning() << "Password is empty!"; - return; + return false; } if (_configured && _storage->addUser(username, password).isValid()) { out << "Added user " << username << " successfully!" << endl; + return true; } else { qWarning() << "Unable to add user:" << qPrintable(username); + return false; } } -void Core::changeUserPass(const QString &username) +bool Core::changeUserPass(const QString &username) { QTextStream out(stdout); QTextStream in(stdin); UserId userId = _storage->getUserId(username); if (!userId.isValid()) { out << "User " << username << " does not exist." << endl; - return; + return false; } out << "Change password for user: " << username << endl; @@ -803,22 +948,33 @@ void Core::changeUserPass(const QString &username) if (password != password2) { qWarning() << "Passwords don't match!"; - return; + return false; } if (password.isEmpty()) { qWarning() << "Password is empty!"; - return; + return false; } if (_configured && _storage->updateUser(userId, password)) { out << "Password changed successfully!" << endl; + return true; } else { qWarning() << "Failed to change password!"; + return false; } } +bool Core::changeUserPassword(UserId userId, const QString &password) +{ + if (!isConfigured() || !userId.isValid()) + return false; + + return instance()->_storage->updateUser(userId, password); +} + + AbstractSqlMigrationReader *Core::getMigrationReader(Storage *storage) { if (!storage) @@ -849,12 +1005,22 @@ AbstractSqlMigrationWriter *Core::getMigrationWriter(Storage *storage) } -void Core::saveBackendSettings(const QString &backend, const QVariantMap &settings) +bool Core::saveBackendSettings(const QString &backend, const QVariantMap &settings) { QVariantMap dbsettings; dbsettings["Backend"] = backend; dbsettings["ConnectionProperties"] = settings; - CoreSettings().setStorageSettings(dbsettings); + CoreSettings s = CoreSettings(); + s.setStorageSettings(dbsettings); + return s.sync(); +} + +void Core::saveAuthBackendSettings(const QString &backend, const QVariantMap &settings) +{ + QVariantMap dbsettings; + dbsettings["AuthBackend"] = backend; + dbsettings["ConnectionProperties"] = settings; + CoreSettings().setAuthSettings(dbsettings); }