X-Git-Url: https://git.quassel-irc.org/?a=blobdiff_plain;f=src%2Fcore%2Fcoreauthhandler.cpp;h=8d39d06d1a97122c3a0872efa0c1a8580633094a;hb=df38a9238d603ec8d2040619befa50980d994916;hp=d559e44e162c505fe6cbbe8b10309e2d5f929bbe;hpb=c1cf157116de7fc3da96203aa6f03c38c7ebb650;p=quassel.git diff --git a/src/core/coreauthhandler.cpp b/src/core/coreauthhandler.cpp index d559e44e..8d39d06d 100644 --- a/src/core/coreauthhandler.cpp +++ b/src/core/coreauthhandler.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2018 by the Quassel Project * + * Copyright (C) 2005-2020 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -20,18 +20,21 @@ #include "coreauthhandler.h" +#include + #ifdef HAVE_SSL # include #endif #include "core.h" -#include "logmessage.h" - -using namespace Protocol; CoreAuthHandler::CoreAuthHandler(QTcpSocket* socket, QObject* parent) : AuthHandler(parent) , _peer(nullptr) + , _metricsServer(Core::instance()->metricsServer()) + , _proxyReceived(false) + , _proxyLine({}) + , _useProxyLine(false) , _magicReceived(false) , _legacy(false) , _clientRegistered(false) @@ -45,13 +48,37 @@ CoreAuthHandler::CoreAuthHandler(QTcpSocket* socket, QObject* parent) void CoreAuthHandler::onReadyRead() { - if (socket()->bytesAvailable() < 4) - return; - // once we have selected a peer, we certainly don't want to read more data! if (_peer) return; + if (!_proxyReceived) { + quint32 magic; + socket()->peek((char*) &magic, 4); + magic = qFromBigEndian(magic); + + if (magic == Protocol::proxyMagic) { + if (!socket()->canReadLine()) { + return; + } + QByteArray line = socket()->readLine(108); + _proxyLine = ProxyLine::parseProxyLine(line); + if (_proxyLine.protocol != QAbstractSocket::UnknownNetworkLayerProtocol) { + QList subnets = Quassel::optionValue("proxy-cidr").split(","); + for (const QString& subnet : subnets) { + if (socket()->peerAddress().isInSubnet(QHostAddress::parseSubnet(subnet))) { + _useProxyLine = true; + break; + } + } + } + } + _proxyReceived = true; + } + + if (socket()->bytesAvailable() < 4) + return; + if (!_magicReceived) { quint32 magic; socket()->peek((char*)&magic, 4); @@ -101,7 +128,7 @@ void CoreAuthHandler::onReadyRead() RemotePeer* peer = PeerFactory::createPeer(_supportedProtos, this, socket(), level, this); if (!peer) { - qWarning() << "Received invalid handshake data from client" << socket()->peerAddress().toString(); + qWarning() << "Received invalid handshake data from client" << hostAddress().toString(); close(); return; } @@ -130,6 +157,9 @@ void CoreAuthHandler::setPeer(RemotePeer* peer) qDebug().nospace() << "Using " << qPrintable(peer->protocolName()) << "..."; _peer = peer; + if (_proxyLine.protocol != QAbstractSocket::UnknownNetworkLayerProtocol) { + _peer->setProxyLine(_proxyLine); + } disconnect(socket(), &QIODevice::readyRead, this, &CoreAuthHandler::onReadyRead); } @@ -141,24 +171,24 @@ void CoreAuthHandler::onProtocolVersionMismatch(int actual, int expected) "This core needs at least client/core protocol version %1 (got: %2).
" "Please consider upgrading your client.") .arg(expected, actual); - _peer->dispatch(ClientDenied(errorString)); + _peer->dispatch(Protocol::ClientDenied(errorString)); _peer->close(); } bool CoreAuthHandler::checkClientRegistered() { if (!_clientRegistered) { - qWarning() << qPrintable(tr("Client")) << qPrintable(socket()->peerAddress().toString()) + qWarning() << qPrintable(tr("Client")) << qPrintable(hostAddress().toString()) << qPrintable(tr("did not send a registration message before trying to login, rejecting.")); _peer->dispatch( - ClientDenied(tr("Client not initialized!
You need to send a registration message before trying to login."))); + Protocol::ClientDenied(tr("Client not initialized!
You need to send a registration message before trying to login."))); _peer->close(); return false; } return true; } -void CoreAuthHandler::handle(const RegisterClient& msg) +void CoreAuthHandler::handle(const Protocol::RegisterClient& msg) { bool useSsl; if (_legacy) @@ -167,8 +197,8 @@ void CoreAuthHandler::handle(const RegisterClient& msg) useSsl = _connectionFeatures & Protocol::Encryption; if (Quassel::isOptionSet("require-ssl") && !useSsl && !_peer->isLocal()) { - quInfo() << qPrintable(tr("SSL required but non-SSL connection attempt from %1").arg(socket()->peerAddress().toString())); - _peer->dispatch(ClientDenied(tr("SSL is required!
You need to use SSL in order to connect to this core."))); + qInfo() << qPrintable(tr("SSL required but non-SSL connection attempt from %1").arg(hostAddress().toString())); + _peer->dispatch(Protocol::ClientDenied(tr("SSL is required!
You need to use SSL in order to connect to this core."))); _peer->close(); return; } @@ -187,7 +217,7 @@ void CoreAuthHandler::handle(const RegisterClient& msg) } } - _peer->dispatch(ClientRegistered(Quassel::Features{}, configured, backends, authenticators, useSsl)); + _peer->dispatch(Protocol::ClientRegistered(Quassel::Features{}, configured, backends, authenticators, useSsl)); // useSsl is only used for the legacy protocol if (_legacy && useSsl) @@ -196,7 +226,7 @@ void CoreAuthHandler::handle(const RegisterClient& msg) _clientRegistered = true; } -void CoreAuthHandler::handle(const SetupData& msg) +void CoreAuthHandler::handle(const Protocol::SetupData& msg) { if (!checkClientRegistered()) return; @@ -204,60 +234,76 @@ void CoreAuthHandler::handle(const SetupData& msg) // The default parameter to authenticator is Database. // Maybe this should be hardcoded elsewhere, i.e. as a define. QString authenticator = msg.authenticator; - quInfo() << "[" << authenticator << "]"; + qInfo() << "[" << authenticator << "]"; if (authenticator.trimmed().isEmpty()) { authenticator = QString("Database"); } QString result = Core::setup(msg.adminUser, msg.adminPassword, msg.backend, msg.setupData, authenticator, msg.authSetupData); if (!result.isEmpty()) - _peer->dispatch(SetupFailed(result)); + _peer->dispatch(Protocol::SetupFailed(result)); else - _peer->dispatch(SetupDone()); + _peer->dispatch(Protocol::SetupDone()); } -void CoreAuthHandler::handle(const Login& msg) +void CoreAuthHandler::handle(const Protocol::Login& msg) { if (!checkClientRegistered()) return; if (!Core::isConfigured()) { - qWarning() << qPrintable(tr("Client")) << qPrintable(socket()->peerAddress().toString()) + qWarning() << qPrintable(tr("Client")) << qPrintable(hostAddress().toString()) << qPrintable(tr("attempted to login before the core was configured, rejecting.")); - _peer->dispatch(ClientDenied( + _peer->dispatch(Protocol::ClientDenied( tr("Attempted to login before core was configured!
The core must be configured before attempting to login."))); return; } // First attempt local auth using the real username and password. // If that fails, move onto the auth provider. - UserId uid = Core::validateUser(msg.user, msg.password); + + // Check to see if the user has the "Database" authenticator configured. + UserId uid = 0; + if (Core::getUserAuthenticator(msg.user) == "Database") { + uid = Core::validateUser(msg.user, msg.password); + } + + // If they did not, *or* if the database login fails, try to use a different authenticator. + // TODO: this logic should likely be moved into Core::authenticateUser in the future. + // Right now a core can only have one authenticator configured; this might be something + // to change in the future. if (uid == 0) { uid = Core::authenticateUser(msg.user, msg.password); } if (uid == 0) { - quInfo() << qPrintable(tr("Invalid login attempt from %1 as \"%2\"").arg(socket()->peerAddress().toString(), msg.user)); - _peer->dispatch(LoginFailed(tr( + qInfo() << qPrintable(tr("Invalid login attempt from %1 as \"%2\"").arg(hostAddress().toString(), msg.user)); + _peer->dispatch(Protocol::LoginFailed(tr( "Invalid username or password!
The username/password combination you supplied could not be found in the database."))); + if (_metricsServer) { + _metricsServer->addLoginAttempt(msg.user, false); + } return; } - _peer->dispatch(LoginSuccess()); + _peer->dispatch(Protocol::LoginSuccess()); + if (_metricsServer) { + _metricsServer->addLoginAttempt(uid, true); + } - quInfo() << qPrintable(tr("Client %1 initialized and authenticated successfully as \"%2\" (UserId: %3).") - .arg(socket()->peerAddress().toString(), msg.user, QString::number(uid.toInt()))); + qInfo() << qPrintable(tr("Client %1 initialized and authenticated successfully as \"%2\" (UserId: %3).") + .arg(_peer->address(), msg.user, QString::number(uid.toInt()))); const auto& clientFeatures = _peer->features(); auto unsupported = clientFeatures.toStringList(false); if (!unsupported.isEmpty()) { if (unsupported.contains("NoFeatures")) - quInfo() << qPrintable(tr("Client does not support extended features.")); + qInfo() << qPrintable(tr("Client does not support extended features.")); else - quInfo() << qPrintable(tr("Client does not support the following features: %1").arg(unsupported.join(", "))); + qInfo() << qPrintable(tr("Client does not support the following features: %1").arg(unsupported.join(", "))); } if (!clientFeatures.unknownFeatures().isEmpty()) { - quInfo() << qPrintable(tr("Client supports unknown features: %1").arg(clientFeatures.unknownFeatures().join(", "))); + qInfo() << qPrintable(tr("Client supports unknown features: %1").arg(clientFeatures.unknownFeatures().join(", "))); } disconnect(socket(), nullptr, this, nullptr); @@ -268,6 +314,24 @@ void CoreAuthHandler::handle(const Login& msg) emit handshakeComplete(_peer, uid); } +QHostAddress CoreAuthHandler::hostAddress() const +{ + if (_useProxyLine) { + return _proxyLine.sourceHost; + } + else if (socket()) { + return socket()->peerAddress(); + } + + return {}; +} + +bool CoreAuthHandler::isLocal() const +{ + return hostAddress() == QHostAddress::LocalHost || + hostAddress() == QHostAddress::LocalHostIPv6; +} + /*** SSL Stuff ***/ void CoreAuthHandler::startSsl()