aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/Utilities/Tuples.h34
-rw-r--r--src/server/game/Server/Packets/PacketUtilities.cpp39
-rw-r--r--src/server/game/Server/Packets/PacketUtilities.h96
-rw-r--r--src/server/game/Server/WorldSession.cpp16
-rw-r--r--src/server/shared/Packets/ByteBuffer.cpp12
-rw-r--r--src/server/shared/Packets/ByteBuffer.h2
6 files changed, 192 insertions, 7 deletions
diff --git a/src/common/Utilities/Tuples.h b/src/common/Utilities/Tuples.h
new file mode 100644
index 00000000000..73337ebd9f5
--- /dev/null
+++ b/src/common/Utilities/Tuples.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef Tuples_h__
+#define Tuples_h__
+
+#include <tuple>
+
+namespace Trinity
+{
+ template <typename T, typename Tuple>
+ struct has_type;
+
+ template <typename T, typename... Us>
+ struct has_type<T, std::tuple<Us...>> : std::disjunction<std::is_same<T, Us>...>
+ {
+ };
+}
+
+#endif // Tuples_h__
diff --git a/src/server/game/Server/Packets/PacketUtilities.cpp b/src/server/game/Server/Packets/PacketUtilities.cpp
index 99f3decd0e1..426b3be9b8f 100644
--- a/src/server/game/Server/Packets/PacketUtilities.cpp
+++ b/src/server/game/Server/Packets/PacketUtilities.cpp
@@ -16,9 +16,48 @@
*/
#include "PacketUtilities.h"
+#include "Hyperlinks.h"
#include "Errors.h"
+#include <utf8.h>
#include <sstream>
+WorldPackets::InvalidStringValueException::InvalidStringValueException(std::string const& value) : ByteBufferInvalidValueException("string", value.c_str())
+{
+}
+
+WorldPackets::InvalidUtf8ValueException::InvalidUtf8ValueException(std::string const& value) : InvalidStringValueException(value)
+{
+}
+
+WorldPackets::InvalidHyperlinkException::InvalidHyperlinkException(std::string const& value) : InvalidStringValueException(value)
+{
+}
+
+WorldPackets::IllegalHyperlinkException::IllegalHyperlinkException(std::string const& value) : InvalidStringValueException(value)
+{
+}
+
+bool WorldPackets::Strings::Utf8::Validate(std::string const& value)
+{
+ if (!utf8::is_valid(value.begin(), value.end()))
+ throw InvalidUtf8ValueException(value);
+ return true;
+}
+
+bool WorldPackets::Strings::Hyperlinks::Validate(std::string const& value)
+{
+ if (!Trinity::Hyperlinks::CheckAllLinks(value))
+ throw InvalidHyperlinkException(value);
+ return true;
+}
+
+bool WorldPackets::Strings::NoHyperlinks::Validate(std::string const& value)
+{
+ if (value.find('|') != std::string::npos)
+ throw IllegalHyperlinkException(value);
+ return true;
+}
+
WorldPackets::PacketArrayMaxCapacityException::PacketArrayMaxCapacityException(std::size_t requestedSize, std::size_t sizeLimit)
{
std::ostringstream builder;
diff --git a/src/server/game/Server/Packets/PacketUtilities.h b/src/server/game/Server/Packets/PacketUtilities.h
index 8b119cf1f61..3bb3443ff06 100644
--- a/src/server/game/Server/Packets/PacketUtilities.h
+++ b/src/server/game/Server/Packets/PacketUtilities.h
@@ -20,11 +20,107 @@
#include "ByteBuffer.h"
#include "Duration.h"
+#include "Tuples.h"
#include <boost/container/static_vector.hpp>
#include <ctime>
namespace WorldPackets
{
+ class InvalidStringValueException : public ByteBufferInvalidValueException
+ {
+ public:
+ InvalidStringValueException(std::string const& value);
+
+ std::string const& GetInvalidValue() const { return _value; }
+
+ private:
+ std::string _value;
+ };
+
+ class InvalidUtf8ValueException : public InvalidStringValueException
+ {
+ public:
+ InvalidUtf8ValueException(std::string const& value);
+ };
+
+ class InvalidHyperlinkException : public InvalidStringValueException
+ {
+ public:
+ InvalidHyperlinkException(std::string const& value);
+ };
+
+ class IllegalHyperlinkException : public InvalidStringValueException
+ {
+ public:
+ IllegalHyperlinkException(std::string const& value);
+ };
+
+ namespace Strings
+ {
+ struct RawBytes { static bool Validate(std::string const& /*value*/) { return true; } };
+ template<std::size_t MaxBytesWithoutNullTerminator>
+ struct ByteSize { static bool Validate(std::string const& value) { return value.size() <= MaxBytesWithoutNullTerminator; } };
+ struct Utf8 { static bool Validate(std::string const& value); };
+ struct Hyperlinks { static bool Validate(std::string const& value); };
+ struct NoHyperlinks { static bool Validate(std::string const& value); };
+ }
+
+ /**
+ * Utility class for automated prevention of invalid strings in client packets
+ */
+ template<std::size_t MaxBytesWithoutNullTerminator, typename... Validators>
+ class String
+ {
+ using ValidatorList = std::conditional_t<!Trinity::has_type<Strings::RawBytes, std::tuple<Validators...>>::value,
+ std::tuple<Strings::ByteSize<MaxBytesWithoutNullTerminator>, Strings::Utf8, Validators...>,
+ std::tuple<Strings::ByteSize<MaxBytesWithoutNullTerminator>, Validators...>>;
+
+ public:
+ bool empty() const { return _storage.empty(); }
+ char const* c_str() const { return _storage.c_str(); }
+
+ operator std::string&() { return _storage; }
+ operator std::string const&() const { return _storage; }
+
+ std::string&& Move() { return std::move(_storage); }
+
+ friend ByteBuffer& operator>>(ByteBuffer& data, String& value)
+ {
+ std::string string = data.ReadCString(false);
+ Validate(string);
+ value._storage = std::move(string);
+ return data;
+ }
+
+ String& operator=(std::string const& value)
+ {
+ Validate(value);
+ _storage = value;
+ return *this;
+ }
+
+ String& operator=(std::string&& value)
+ {
+ Validate(value);
+ _storage = std::move(value);
+ return *this;
+ }
+
+ private:
+ static bool Validate(std::string const& value)
+ {
+ return ValidateNth(value, std::make_index_sequence<std::tuple_size_v<ValidatorList>>{});
+ }
+
+ template<std::size_t... indexes>
+ static bool ValidateNth(std::string const& value, std::index_sequence<indexes...>)
+ {
+ return (std::tuple_element_t<indexes, ValidatorList>::Validate(value) && ...);
+ }
+
+ std::string _storage;
+ };
+
class PacketArrayMaxCapacityException : public ByteBufferException
{
public:
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 3a14cf48785..942b29be1dc 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -425,6 +425,22 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
break;
}
}
+ catch (WorldPackets::InvalidHyperlinkException const& ihe)
+ {
+ TC_LOG_ERROR("network", "%s sent %s with an invalid link:\n%s", GetPlayerInfo().c_str(),
+ GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), ihe.GetInvalidValue().c_str());
+
+ if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK))
+ KickPlayer();
+ }
+ catch (WorldPackets::IllegalHyperlinkException const& ihe)
+ {
+ TC_LOG_ERROR("network", "%s sent %s which illegally contained a hyperlink:\n%s", GetPlayerInfo().c_str(),
+ GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), ihe.GetInvalidValue().c_str());
+
+ if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK))
+ KickPlayer();
+ }
catch (WorldPackets::PacketArrayMaxCapacityException const& pamce)
{
TC_LOG_ERROR("network", "PacketArrayMaxCapacityException: %s while parsing %s from %s.",
diff --git a/src/server/shared/Packets/ByteBuffer.cpp b/src/server/shared/Packets/ByteBuffer.cpp
index 6c1ed3842cc..f8470332893 100644
--- a/src/server/shared/Packets/ByteBuffer.cpp
+++ b/src/server/shared/Packets/ByteBuffer.cpp
@@ -39,16 +39,16 @@ ByteBufferPositionException::ByteBufferPositionException(size_t pos, size_t size
message().assign(ss.str());
}
-ByteBufferInvalidValueException::ByteBufferInvalidValueException(char const* type, size_t pos)
+ByteBufferInvalidValueException::ByteBufferInvalidValueException(char const* type, char const* value)
{
- message().assign(Trinity::StringFormat("Invalid %s value found in ByteBuffer at pos " SZFMTD, type, pos));
+ message().assign(Trinity::StringFormat("Invalid %s value (%s) found in ByteBuffer", type, value));
}
ByteBuffer& ByteBuffer::operator>>(float& value)
{
value = read<float>();
if (!std::isfinite(value))
- throw ByteBufferInvalidValueException("float", _rpos - sizeof(float));
+ throw ByteBufferInvalidValueException("float", "infinity");
return *this;
}
@@ -56,7 +56,7 @@ ByteBuffer& ByteBuffer::operator>>(double& value)
{
value = read<double>();
if (!std::isfinite(value))
- throw ByteBufferInvalidValueException("double", _rpos - sizeof(double));
+ throw ByteBufferInvalidValueException("double", "infinity");
return *this;
}
@@ -71,7 +71,7 @@ std::string ByteBuffer::ReadCString(bool requireValidUtf8 /*= true*/)
value += c;
}
if (requireValidUtf8 && !utf8::is_valid(value.begin(), value.end()))
- throw ByteBufferInvalidValueException("string", _rpos - value.length() - 1);
+ throw ByteBufferInvalidValueException("string", value.c_str());
return value;
}
@@ -87,7 +87,7 @@ std::string ByteBuffer::ReadString(uint32 length, bool requireValidUtf8 /*= true
std::string value(reinterpret_cast<char const*>(&_storage[_rpos]), length);
_rpos += length;
if (requireValidUtf8 && !utf8::is_valid(value.begin(), value.end()))
- throw ByteBufferInvalidValueException("string", _rpos - value.length() - 1);
+ throw ByteBufferInvalidValueException("string", value.c_str());
return value;
}
diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h
index 553c1a4c4ff..32f6bcbaee9 100644
--- a/src/server/shared/Packets/ByteBuffer.h
+++ b/src/server/shared/Packets/ByteBuffer.h
@@ -53,7 +53,7 @@ public:
class TC_SHARED_API ByteBufferInvalidValueException : public ByteBufferException
{
public:
- ByteBufferInvalidValueException(char const* type, size_t pos);
+ ByteBufferInvalidValueException(char const* type, char const* value);
~ByteBufferInvalidValueException() noexcept = default;
};