summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2014-03-28 01:16:05 +0100
committerFlorent Le Coz <louiz@louiz.org>2014-03-28 01:16:05 +0100
commit3c5f823621e170aaa5ae9f240335bea49d470da5 (patch)
tree3a052d91885b7629c8066badac4706ec5f984a8d /src
parent2ffbfb71ddeb791e6a5ab1955208067f2856aeea (diff)
downloadbiboumi-3c5f823621e170aaa5ae9f240335bea49d470da5.tar.gz
biboumi-3c5f823621e170aaa5ae9f240335bea49d470da5.tar.bz2
biboumi-3c5f823621e170aaa5ae9f240335bea49d470da5.tar.xz
biboumi-3c5f823621e170aaa5ae9f240335bea49d470da5.zip
Send a stanza error when receiving bad stanzas
Whether this is a bad-request (missing XML attributes or elements) or an internal server error.
Diffstat (limited to 'src')
-rw-r--r--src/xmpp/xmpp_component.cpp120
-rw-r--r--src/xmpp/xmpp_component.hpp6
2 files changed, 116 insertions, 10 deletions
diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp
index 94ad634..1eea8ba 100644
--- a/src/xmpp/xmpp_component.cpp
+++ b/src/xmpp/xmpp_component.cpp
@@ -1,4 +1,5 @@
#include <utils/make_unique.hpp>
+#include <utils/scopeguard.hpp>
#include <logger/logger.hpp>
#include <xmpp/xmpp_component.hpp>
@@ -204,6 +205,38 @@ void XmppComponent::send_stream_error(const std::string& name, const std::string
this->send_stanza(node);
}
+void XmppComponent::send_stanza_error(const std::string& kind, const std::string& to, const std::string& from,
+ const std::string& id, const std::string& error_type,
+ const std::string& defined_condition, const std::string& text)
+{
+ Stanza node(kind);
+ if (!to.empty())
+ node["to"] = to;
+ if (!from.empty())
+ node["from"] = from;
+ if (!id.empty())
+ node["id"] = id;
+ node["type"] = "error";
+ XmlNode error("error");
+ error["type"] = error_type;
+ XmlNode inner_error(defined_condition);
+ inner_error["xmlns"] = STANZA_NS;
+ inner_error.close();
+ error.add_child(std::move(inner_error));
+ if (!text.empty())
+ {
+ XmlNode text_node("text");
+ text_node["xmlns"] = STANZA_NS;
+ text_node.set_inner(text);
+ text_node.close();
+ error.add_child(std::move(text_node));
+ }
+ error.close();
+ node.add_child(std::move(error));
+ node.close();
+ this->send_stanza(node);
+}
+
void XmppComponent::close_document()
{
log_debug("XMPP SENDING: </stream:stream>");
@@ -222,6 +255,14 @@ void XmppComponent::handle_handshake(const Stanza& stanza)
void XmppComponent::handle_presence(const Stanza& stanza)
{
+ std::string id;
+ try {
+ id = stanza["id"];
+ } catch (const AttributeNotFound&) {}
+ utils::ScopeGuard malformed_stanza_error([this, &id](){
+ this->send_stanza_error("presence", "", this->served_hostname, id,
+ "modify", "bad-request", "");
+ });
Bridge* bridge = this->get_user_bridge(stanza["from"]);
Jid to(stanza["to"]);
Iid iid(to.local);
@@ -230,6 +271,20 @@ void XmppComponent::handle_presence(const Stanza& stanza)
type = stanza["type"];
}
catch (const AttributeNotFound&) {}
+ malformed_stanza_error.disable();
+
+ // An error stanza is sent whenever we exit this function without
+ // disabling this scopeguard. If error_type and error_name are not
+ // changed, the error signaled is internal-server-error. Change their
+ // value to signal an other kind of error. For example
+ // feature-not-implemented, etc. Any non-error process should reach the
+ // stanza_error.disable() call at the end of the function.
+ std::string error_type("cancel");
+ std::string error_name("internal-server-error");
+ utils::ScopeGuard stanza_error([this, &stanza, &error_type, &error_name, &id](){
+ this->send_stanza_error("presence", stanza["from"], stanza["to"], id,
+ error_type, error_name, "");
+ });
if (!iid.chan.empty() && !iid.server.empty())
{ // presence toward a MUC that corresponds to an irc channel
@@ -252,15 +307,37 @@ void XmppComponent::handle_presence(const Stanza& stanza)
if (type.empty())
this->send_invalid_room_error(to.local, to.resource, stanza["from"]);
}
+ stanza_error.disable();
}
void XmppComponent::handle_message(const Stanza& stanza)
{
+ std::string id;
+ try {
+ id = stanza["id"];
+ } catch (const AttributeNotFound&) {}
+ utils::ScopeGuard malformed_stanza_error([this, &id](){
+ this->send_stanza_error("message", "", this->served_hostname, id,
+ "modify", "bad-request", "");
+ });
Bridge* bridge = this->get_user_bridge(stanza["from"]);
Jid to(stanza["to"]);
Iid iid(to.local);
+ std::string type;
+ try {
+ type = stanza["type"];
+ }
+ catch (const AttributeNotFound&) {}
+ malformed_stanza_error.disable();
+
+ std::string error_type("cancel");
+ std::string error_name("internal-server-error");
+ utils::ScopeGuard stanza_error([this, &stanza, &error_type, &error_name, &id](){
+ this->send_stanza_error("message", stanza["from"], stanza["to"], id,
+ error_type, error_name, "");
+ });
XmlNode* body = stanza.get_child(COMPONENT_NS":body");
- if (stanza["type"] == "groupchat")
+ if (type == "groupchat")
{
if (to.resource.empty())
if (body && !body->get_inner().empty())
@@ -274,25 +351,37 @@ void XmppComponent::handle_message(const Stanza& stanza)
if (body && !body->get_inner().empty())
bridge->send_private_message(iid, body->get_inner());
}
+ stanza_error.disable();
}
void XmppComponent::handle_iq(const Stanza& stanza)
{
+ std::string id;
+ try {
+ id = stanza["id"];
+ } catch (const AttributeNotFound&) {}
+ utils::ScopeGuard malformed_stanza_error([this, &id](){
+ this->send_stanza_error("iq", "", this->served_hostname, id,
+ "modify", "bad-request", "");
+ });
Bridge* bridge = this->get_user_bridge(stanza["from"]);
Jid to(stanza["to"]);
- std::string type;
- try {
- type = stanza["type"];
- }
- catch (const AttributeNotFound&)
- { return; }
+ std::string type = stanza["type"];
+ malformed_stanza_error.disable();
+
+ std::string error_type("cancel");
+ std::string error_name("internal-server-error");
+ utils::ScopeGuard stanza_error([this, &stanza, &error_type, &error_name, &id](){
+ this->send_stanza_error("iq", stanza["from"], stanza["to"], id,
+ error_type, error_name, "");
+ });
if (type == "set")
{
XmlNode* query;
if ((query = stanza.get_child(MUC_ADMIN_NS":query")))
{
- XmlNode* child;
- if ((child = query->get_child(MUC_ADMIN_NS":item")))
+ const XmlNode* child = query->get_child(MUC_ADMIN_NS":item");
+ if (child)
{
std::string nick;
std::string role;
@@ -301,7 +390,11 @@ void XmppComponent::handle_iq(const Stanza& stanza)
role = (*child)["role"];
}
catch (const AttributeNotFound&)
- { return; }
+ {
+ error_type = "modify";
+ error_name = "bad-request";
+ return;
+ }
if (!nick.empty() && role == "none")
{
std::string reason;
@@ -314,6 +407,13 @@ void XmppComponent::handle_iq(const Stanza& stanza)
}
}
}
+ else
+ {
+ error_type = "cancel";
+ error_name = "feature-not-implemented";
+ return;
+ }
+ stanza_error.disable();
}
void XmppComponent::handle_error(const Stanza& stanza)
diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp
index d4853c8..5a5d3d8 100644
--- a/src/xmpp/xmpp_component.hpp
+++ b/src/xmpp/xmpp_component.hpp
@@ -69,6 +69,12 @@ public:
*/
void send_stream_error(const std::string& message, const std::string& explanation);
/**
+ * Send error stanza, described in http://xmpp.org/rfcs/rfc6120.html#stanzas-error
+ */
+ void send_stanza_error(const std::string& kind, const std::string& to, const std::string& from,
+ const std::string& id, const std::string& error_type,
+ const std::string& defined_condition, const std::string& text);
+ /**
* Send the closing signal for our document (not closing the connection though).
*/
void close_document();