[asterisk-commits] mmichelson: branch group/CCSS r232948 - /team/group/CCSS/channels/chan_sip.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Dec 3 18:25:25 CST 2009
Author: mmichelson
Date: Thu Dec 3 18:25:22 2009
New Revision: 232948
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=232948
Log:
Create a basic PDIF validation function.
This doesn't do any sort of application-level validation.
It simply makes sure that the PIDF document contained in the
body of a SIP message is compliant with RFC 3863 in that it
contains all mandatory elements and that these mandatory
elements contain their mandatory attributes.
Modified:
team/group/CCSS/channels/chan_sip.c
Modified: team/group/CCSS/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/channels/chan_sip.c?view=diff&rev=232948&r1=232947&r2=232948
==============================================================================
--- team/group/CCSS/channels/chan_sip.c (original)
+++ team/group/CCSS/channels/chan_sip.c Thu Dec 3 18:25:22 2009
@@ -270,6 +270,7 @@
#include "asterisk/cel.h"
#include "asterisk/strings.h"
#include "asterisk/ccss.h"
+#include "asterisk/xml.h"
/*** DOCUMENTATION
<application name="SIPDtmfMode" language="en_US">
@@ -23316,6 +23317,148 @@
return SIP_PUBLISH_UNKNOWN;
}
+/*!
+ * \brief Makes sure that body is properly formatted PIDF
+ *
+ * Specifically, we check that the document has a "presence" element
+ * at the root and that within that, there is at least one "tuple" element
+ * that contains a "status" element.
+ *
+ * XXX This function currently assumes a default namespace is used. Of course
+ * if you're not using a default namespace, you're probably a stupid jerk anyway.
+ *
+ * \param req The SIP request to check
+ * \retval FALSE The XML was malformed or the basic PIDF structure was marred
+ * \retval TRUE The PIDF document is of a valid format
+ */
+static int sip_pidf_validate(struct sip_request *req)
+{
+ struct ast_xml_doc *doc;
+ struct ast_xml_node *root_node;
+ struct ast_xml_node *node_iterator;
+ struct ast_xml_node *child_nodes;
+ int content_length;
+ const char *content_length_str = get_header(req, "Content-Length");
+ const char *content_type = get_header(req, "Content-Type");
+ const char *entity;
+ const char *namespace;
+
+ if (ast_strlen_zero(content_type) || strcmp(content_type, "application/xml+pidf")) {
+ ast_log(LOG_WARNING, "Content type is not PIDF\n");
+ return FALSE;
+ }
+
+ if (ast_strlen_zero(content_length_str)) {
+ ast_log(LOG_WARNING, "No content length. Can't determine bounds of PIDF document\n");
+ return FALSE;
+ }
+
+ if (sscanf(content_length_str, "%30d", &content_length) != 1) {
+ ast_log(LOG_WARNING, "Invalid content length provided\n");
+ return FALSE;
+ }
+
+ if (!(doc = ast_xml_read_memory(REQ_OFFSET_TO_STR(req, line[0]), content_length))) {
+ ast_log(LOG_WARNING, "Unable to open XML PIDF document. Is it malformed?\n");
+ return FALSE;
+ }
+
+ /* Okay, we managed to open the document! YAY! Now, let's start making sure it's all PIDF-ified
+ * correctly.
+ */
+ root_node = ast_xml_get_root(doc);
+ if (strcmp(ast_xml_node_get_name(root_node), "presence")) {
+ ast_log(LOG_WARNING, "Root node of PIDF document is not 'presence'. Invalid\n");
+ goto fail;
+ }
+
+ /* The presence element must have an entity attribute and an xmlns attribute. Furthermore
+ * the xmlns attribute must be "urn:ietf:params:xml:ns:pidf"
+ */
+ if (!(entity = ast_xml_get_attribute(root_node, "entity"))) {
+ ast_log(LOG_WARNING, "Presence element of PIDF document has no 'entity' attribute\n");
+ goto fail;
+ }
+ /* We're not interested in what the entity is, just that it exists */
+ ast_xml_free_attr(entity);
+
+ if (!(namespace = ast_xml_get_attribute(root_node, "xmlns"))) {
+ ast_log(LOG_WARNING, "Presence element of PIDF document has no 'xmlns' attribute\n");
+ goto fail;
+ }
+
+ if (strcmp(namespace, "urn:ietf:params:xml:ns:pidf")) {
+ ast_log(LOG_WARNING, "Improper XML namespace in PIDF document\n");
+ ast_xml_free_attr(namespace);
+ goto fail;
+ }
+
+ ast_xml_free_attr(namespace);
+
+ if (!(child_nodes = ast_xml_node_get_children(root_node))) {
+ ast_log(LOG_WARNING, "PIDF document has no elements as children of 'presence'. Invalid\n");
+ goto fail;
+ }
+
+ /* Check for tuple elements. RFC 3863 says that PIDF documents can have any number of
+ * tuples, including 0. The big thing here is that if there are tuple elements present,
+ * they have to have a single status element within.
+ *
+ * The RFC is worded such that tuples should appear as the first elements as children of
+ * the presence element. However, we'll be accepting of documents which may place other elements
+ * before the tuple(s).
+ */
+ for (node_iterator = child_nodes; node_iterator;
+ node_iterator = ast_xml_node_get_next(node_iterator)) {
+ struct ast_xml_node *tuple_children;
+ struct ast_xml_node *tuple_children_iterator;
+ const char *id;
+ int status_found = FALSE;
+ if (strcmp(ast_xml_node_get_name(node_iterator), "tuple")) {
+ /* Not a tuple. We don't give a rat's hind quarters */
+ continue;
+ }
+ /* Tuples have to have an id attribute or they're invalid */
+ if (!(id = ast_xml_get_attribute(node_iterator, "id"))) {
+ goto fail;
+ }
+ /* We don't care what it actually is, just that it's there */
+ ast_xml_free_attr(entity);
+ /* This is a tuple. It must have a status element */
+ if (!(tuple_children = ast_xml_node_get_children(node_iterator))) {
+ /* The tuple has no children. It sucks */
+ goto fail;
+ }
+ for (tuple_children_iterator = tuple_children; tuple_children_iterator;
+ tuple_children_iterator = ast_xml_node_get_next(tuple_children_iterator)) {
+ /* Similar to the wording used regarding tuples, the status element should appear
+ * first. However, we will once again relax things and accept the status at any
+ * position. We will enforce that only a single status element can be present.
+ */
+ if (strcmp(ast_xml_node_get_name(tuple_children_iterator), "status")) {
+ /* Not the status, we don't care */
+ continue;
+ }
+ if (status_found == TRUE) {
+ /* THERE CAN BE ONLY ONE!!! */
+ goto fail;
+ }
+ status_found = TRUE;
+ }
+ if (status_found == FALSE) {
+ /* The tuple had no status element... */
+ goto fail;
+ }
+ }
+
+ ast_xml_close(doc);
+ return TRUE;
+
+fail:
+ ast_xml_close(doc);
+ return FALSE;
+}
+
static int cc_esc_publish_initial_handler(struct sip_pvt *pvt, struct sip_request *req, struct event_state_compositor *esc, struct sip_esc_entry *esc_entry)
{
const char *uri = REQ_OFFSET_TO_STR(req, rlPart2);
@@ -23330,9 +23473,7 @@
agent_pvt = agent->private_data;
- /* XXX Add code here to get the body just in case some goofball has decided
- * to send an initial CC PUBLISH with state "open"
- */
+ sip_pidf_validate(req);
agent_pvt->is_available = FALSE;
/* It's possible to get a PUBLISH before we have sent a NOTIFY that a callee is
More information about the asterisk-commits
mailing list