From 838deb445b615aa06829164deb926ad68a42ae30 Mon Sep 17 00:00:00 2001 From: Linus Jahn Date: Wed, 28 Dec 2022 21:58:25 +0100 Subject: Stream: Add IQ response sender check Verifies that the sender of the response is correct, so no evil entity can inject responses. Fixes #510. --- src/base/QXmppStream.cpp | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) (limited to 'src/base/QXmppStream.cpp') diff --git a/src/base/QXmppStream.cpp b/src/base/QXmppStream.cpp index 6b5d9589..c650b8ac 100644 --- a/src/base/QXmppStream.cpp +++ b/src/base/QXmppStream.cpp @@ -33,7 +33,11 @@ using namespace QXmpp::Private; static bool randomSeeded = false; #endif -using IqState = QFutureInterface; +struct IqState +{ + QFutureInterface interface; + QString jid; +}; class QXmppStreamPrivate { @@ -219,7 +223,7 @@ QFuture QXmppStream::sendIq(QXmppIq &&iq) iq.setId(QXmppUtils::generateStanzaUuid()); } - return sendIq(QXmppPacket(iq), iq.id()); + return sendIq(QXmppPacket(iq), iq.id(), iq.to()); } /// @@ -229,7 +233,7 @@ QFuture QXmppStream::sendIq(QXmppIq &&iq) /// /// \since QXmpp 1.5 /// -QFuture QXmppStream::sendIq(QXmppPacket &&packet, const QString &id) +QFuture QXmppStream::sendIq(QXmppPacket &&packet, const QString &id, const QString &to) { using namespace QXmpp; @@ -239,6 +243,12 @@ QFuture QXmppStream::sendIq(QXmppPacket &&packet, const Q SendError::Disconnected }); } + if (to.isEmpty()) { + return makeReadyFuture(SendError { + QStringLiteral("The 'to' address must be set so the stream can match the response."), + SendError::Disconnected }); + } + auto sendFuture = send(std::move(packet)); if (sendFuture.isFinished()) { if (std::holds_alternative(sendFuture.result())) { @@ -249,8 +259,8 @@ QFuture QXmppStream::sendIq(QXmppPacket &&packet, const Q awaitLast(sendFuture, this, [this, id](SendResult result) { if (std::holds_alternative(result)) { if (auto itr = d->runningIqs.find(id); itr != d->runningIqs.end()) { - itr.value().reportResult(std::get(result)); - itr.value().reportFinished(); + itr.value().interface.reportResult(std::get(result)); + itr.value().interface.reportFinished(); d->runningIqs.erase(itr); } @@ -258,9 +268,13 @@ QFuture QXmppStream::sendIq(QXmppPacket &&packet, const Q }); } - IqState interface(IqState::Started); - d->runningIqs.insert(id, interface); - return interface.future(); + IqState state { + QFutureInterface(QFutureInterfaceBase::Started), + to, + }; + auto future = state.interface.future(); + d->runningIqs.insert(id, std::move(state)); + return future; } /// @@ -271,10 +285,10 @@ QFuture QXmppStream::sendIq(QXmppPacket &&packet, const Q void QXmppStream::cancelOngoingIqs() { for (auto &state : d->runningIqs) { - state.reportResult(QXmpp::SendError { + state.interface.reportResult(QXmpp::SendError { QStringLiteral("IQ has been cancelled."), QXmpp::SendError::Disconnected }); - state.reportFinished(); + state.interface.reportFinished(); } d->runningIqs.clear(); } @@ -475,9 +489,13 @@ bool QXmppStream::handleIqResponse(const QDomElement &stanza) if (auto itr = d->runningIqs.find(stanza.attribute(QStringLiteral("id"))); itr != d->runningIqs.end()) { + if (stanza.attribute("from") != itr.value().jid) { + warning(QStringLiteral("Received IQ response to one of our requests from wrong sender. Ignoring.")); + return false; + } - itr.value().reportResult(stanza); - itr.value().reportFinished(); + itr.value().interface.reportResult(stanza); + itr.value().interface.reportFinished(); d->runningIqs.erase(itr); return true; -- cgit v1.2.3