[svn-commits] mmichelson: branch group/CCSS r232948 - /team/group/CCSS/channels/chan_sip.c

SVN commits to the Digium repositories svn-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 svn-commits mailing list