1414
1515#include "msc_xml.h"
1616
17+ static void msc_xml_on_start_elementns (
18+ void * ctx ,
19+ const xmlChar * localname ,
20+ const xmlChar * prefix ,
21+ const xmlChar * URI ,
22+ int nb_namespaces ,
23+ const xmlChar * * namespaces ,
24+ int nb_attributes ,
25+ int nb_defaulted ,
26+ const xmlChar * * attributes
27+ ) {
28+
29+ // get the length of XML tag (localname)
30+ size_t taglen = strlen ((const char * )localname );
31+ modsec_rec * msr = (modsec_rec * )ctx ;
32+ msc_xml_parser_state * xml_parser_state = msr -> xml -> xml_parser_state ;
33+
34+ // pathlen contains the concatenated strings of tags with '.'
35+ // eg xml.root.level1.leaf
36+ xml_parser_state -> pathlen += (taglen + 1 );
37+ char * newpath = apr_pstrcat (msr -> mp , xml_parser_state -> currpath , "." , (char * )localname , NULL );
38+ xml_parser_state -> currpath = newpath ;
39+
40+ int * new_stack_item = (int * )apr_array_push (xml_parser_state -> has_child_stack );
41+ * new_stack_item = 0 ;
42+ xml_parser_state -> depth ++ ;
43+
44+ // if there is an item before the current one we set that has a child
45+ if (xml_parser_state -> depth > 1 ) {
46+ int * parent_stack_item = & ((int * )xml_parser_state -> has_child_stack -> elts )[xml_parser_state -> has_child_stack -> nelts - 2 ];
47+ * parent_stack_item = 1 ;
48+ }
49+
50+ }
51+
52+ static void msc_xml_on_end_elementns (
53+ void * ctx ,
54+ const xmlChar * localname ,
55+ const xmlChar * prefix ,
56+ const xmlChar * URI
57+ ) {
58+
59+ size_t taglen = strlen ((const char * )localname );
60+ modsec_rec * msr = (modsec_rec * )ctx ;
61+ msc_xml_parser_state * xml_parser_state = msr -> xml -> xml_parser_state ;
62+
63+ // if the node is a leaf we add it as argument
64+ // get the top item from the stack which tells this info
65+ int * top_stack_item = apr_array_pop (xml_parser_state -> has_child_stack );
66+ if (* top_stack_item == 0 ) {
67+
68+ if (apr_table_elts (msr -> arguments )-> nelts >= msr -> txcfg -> arguments_limit ) {
69+ if (msr -> txcfg -> debuglog_level >= 4 ) {
70+ msr_log (msr , 4 , "Skipping request argument, over limit (XML): name \"%s\", value \"%s\"" ,
71+ log_escape_ex (msr -> mp , xml_parser_state -> currpath , strlen (xml_parser_state -> currpath )),
72+ log_escape_ex (msr -> mp , xml_parser_state -> currval , strlen (xml_parser_state -> currval )));
73+ }
74+ msr -> msc_reqbody_error = 1 ;
75+ msr -> xml -> xml_error = apr_psprintf (msr -> mp , "More than %ld XML keys" , msr -> txcfg -> arguments_limit );
76+ xmlStopParser ((xmlParserCtxtPtr )msr -> xml -> parsing_ctx_arg );
77+ }
78+ else {
79+
80+ msc_arg * arg = (msc_arg * ) apr_pcalloc (msr -> mp , sizeof (msc_arg ));
81+
82+ arg -> name = xml_parser_state -> currpath ;
83+ arg -> name_len = strlen (arg -> name );
84+ arg -> value = xml_parser_state -> currval ;
85+ arg -> value_len = strlen (xml_parser_state -> currval );
86+ arg -> value_origin_len = arg -> value_len ;
87+ //arg->value_origin_offset = value-base_offset;
88+ arg -> origin = "XML" ;
89+
90+ if (msr -> txcfg -> debuglog_level >= 9 ) {
91+ msr_log (msr , 9 , "Adding XML argument '%s' with value '%s'" ,
92+ xml_parser_state -> currpath , xml_parser_state -> currval );
93+ }
94+
95+ apr_table_addn (msr -> arguments ,
96+ log_escape_nq_ex (msr -> mp , arg -> name , arg -> name_len ), (void * ) arg );
97+ } // end else
98+ } // end top_stack_item == 0
99+
100+ // decrease the length of current path length - +1 because of the '\0'
101+ xml_parser_state -> pathlen -= (taglen + 1 );
102+
103+ // -1 need because we don't need the '.'
104+ char * newpath = apr_pstrndup (msr -> mp , xml_parser_state -> currpath , xml_parser_state -> pathlen - 1 );
105+ xml_parser_state -> currpath = newpath ;
106+
107+ xml_parser_state -> depth -- ;
108+ }
109+
110+ static void msc_xml_on_characters (void * ctx , const xmlChar * ch , int len ) {
111+
112+ modsec_rec * msr = (modsec_rec * )ctx ;
113+ msc_xml_parser_state * xml_parser_state = msr -> xml -> xml_parser_state ;
114+
115+ xml_parser_state -> currval = apr_pstrndup (msr -> mp , (const char * )ch , len );
116+ }
117+
118+
17119static xmlParserInputBufferPtr
18120xml_unload_external_entity (const char * URI , xmlCharEncoding enc ) {
19121 return NULL ;
@@ -37,6 +139,33 @@ int xml_init(modsec_rec *msr, char **error_msg) {
37139 entity = xmlParserInputBufferCreateFilenameDefault (xml_unload_external_entity );
38140 }
39141
142+ if (msr -> txcfg -> parse_xml_into_args != MSC_XML_ARGS_OFF ) {
143+
144+ msr -> xml -> sax_handler = (xmlSAXHandler * )apr_pcalloc (msr -> mp , sizeof (xmlSAXHandler ));
145+ memset (msr -> xml -> sax_handler , 0 , sizeof (xmlSAXHandler ));
146+ if (msr -> xml -> sax_handler == NULL ) {
147+ * error_msg = apr_psprintf (msr -> mp , "XML: Failed to create SAX handler." );
148+ return -1 ;
149+ }
150+
151+ msr -> xml -> sax_handler -> initialized = XML_SAX2_MAGIC ;
152+ msr -> xml -> sax_handler -> startElementNs = msc_xml_on_start_elementns ;
153+ msr -> xml -> sax_handler -> endElementNs = msc_xml_on_end_elementns ;
154+ msr -> xml -> sax_handler -> characters = msc_xml_on_characters ;
155+
156+ // set the parser state struct
157+ msr -> xml -> xml_parser_state = apr_pcalloc (msr -> mp , sizeof (msc_xml_parser_state ));
158+ msr -> xml -> xml_parser_state -> depth = 0 ;
159+ msr -> xml -> xml_parser_state -> pathlen = 4 ; // "xml\0"
160+ msr -> xml -> xml_parser_state -> currpath = apr_pstrdup (msr -> mp , "xml" );
161+ msr -> xml -> xml_parser_state -> currval = NULL ;
162+ msr -> xml -> xml_parser_state -> currpathbufflen = 4 ;
163+ // initialize the stack with item of 10
164+ // this will store the information about nodes
165+ // 10 is just an initial value, it can be automatically incremented
166+ msr -> xml -> xml_parser_state -> has_child_stack = apr_array_make (msr -> mp , 10 , sizeof (int ));
167+ }
168+
40169 return 1 ;
41170}
42171
@@ -68,7 +197,7 @@ int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char
68197 * enable us to pass it the first chunk of data so that
69198 * it can attempt to auto-detect the encoding.
70199 */
71- if (msr -> xml -> parsing_ctx == NULL ) {
200+ if (msr -> xml -> parsing_ctx == NULL && msr -> xml -> parsing_ctx_arg == NULL ) {
72201
73202 /* First invocation. */
74203
@@ -86,18 +215,50 @@ int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char
86215
87216 */
88217
89- msr -> xml -> parsing_ctx = xmlCreatePushParserCtxt (NULL , NULL , buf , size , "body.xml" );
90- if (msr -> xml -> parsing_ctx == NULL ) {
91- * error_msg = apr_psprintf (msr -> mp , "XML: Failed to create parsing context." );
92- return -1 ;
218+ if (msr -> txcfg -> parse_xml_into_args != MSC_XML_ARGS_ONLYARGS ) {
219+ msr -> xml -> parsing_ctx = xmlCreatePushParserCtxt (NULL , NULL , buf , size , "body.xml" );
220+ if (msr -> xml -> parsing_ctx == NULL ) {
221+ * error_msg = apr_psprintf (msr -> mp , "XML: Failed to create parsing context." );
222+ return -1 ;
223+ }
224+ }
225+ if (msr -> txcfg -> parse_xml_into_args != MSC_XML_ARGS_OFF ) {
226+ msr -> xml -> parsing_ctx_arg = xmlCreatePushParserCtxt (
227+ msr -> xml -> sax_handler ,
228+ msr ,
229+ buf ,
230+ size ,
231+ NULL );
232+ if (msr -> xml -> parsing_ctx_arg == NULL ) {
233+ * error_msg = apr_psprintf (msr -> mp , "XML: Failed to create parsing context for ARGS." );
234+ return -1 ;
235+ }
93236 }
94237 } else {
95238
96239 /* Not a first invocation. */
240+ msr_log (msr , 4 , "XML: Continue parsing." );
241+ if (msr -> txcfg -> parse_xml_into_args != MSC_XML_ARGS_ONLYARGS ) {
242+ xmlParseChunk (msr -> xml -> parsing_ctx , buf , size , 0 );
243+ if (msr -> xml -> parsing_ctx -> wellFormed != 1 ) {
244+ * error_msg = apr_psprintf (msr -> mp , "XML: Failed parsing document." );
245+ return -1 ;
246+ }
247+ }
97248
98- xmlParseChunk (msr -> xml -> parsing_ctx , buf , size , 0 );
99- if (msr -> xml -> parsing_ctx -> wellFormed != 1 ) {
100- * error_msg = apr_psprintf (msr -> mp , "XML: Failed parsing document." );
249+ if (msr -> txcfg -> parse_xml_into_args != MSC_XML_ARGS_OFF ) {
250+ if (xmlParseChunk (msr -> xml -> parsing_ctx_arg , buf , size , 0 ) != 0 ) {
251+ if (msr -> xml -> xml_error ) {
252+ * error_msg = msr -> xml -> xml_error ;
253+ }
254+ else {
255+ * error_msg = apr_psprintf (msr -> mp , "XML: Failed parsing document for ARGS." );
256+ }
257+ return -1 ;
258+ }
259+ }
260+ if (msr -> xml -> xml_error ) {
261+ * error_msg = msr -> xml -> xml_error ;
101262 return -1 ;
102263 }
103264 }
@@ -114,23 +275,42 @@ int xml_complete(modsec_rec *msr, char **error_msg) {
114275 * error_msg = NULL ;
115276
116277 /* Only if we have a context, meaning we've done some work. */
117- if (msr -> xml -> parsing_ctx != NULL ) {
118- /* This is how we signalise the end of parsing to libxml. */
119- xmlParseChunk (msr -> xml -> parsing_ctx , NULL , 0 , 1 );
278+ if (msr -> xml -> parsing_ctx != NULL || msr -> xml -> parsing_ctx_arg != NULL ) {
279+ if (msr -> txcfg -> parse_xml_into_args != MSC_XML_ARGS_ONLYARGS ) {
280+ /* This is how we signalise the end of parsing to libxml. */
281+ xmlParseChunk (msr -> xml -> parsing_ctx , NULL , 0 , 1 );
120282
121- /* Preserve the results for our reference. */
122- msr -> xml -> well_formed = msr -> xml -> parsing_ctx -> wellFormed ;
123- msr -> xml -> doc = msr -> xml -> parsing_ctx -> myDoc ;
283+ /* Preserve the results for our reference. */
284+ msr -> xml -> well_formed = msr -> xml -> parsing_ctx -> wellFormed ;
285+ msr -> xml -> doc = msr -> xml -> parsing_ctx -> myDoc ;
124286
125- /* Clean up everything else. */
126- xmlFreeParserCtxt (msr -> xml -> parsing_ctx );
127- msr -> xml -> parsing_ctx = NULL ;
128- msr_log (msr , 4 , "XML: Parsing complete (well_formed %u)." , msr -> xml -> well_formed );
287+ /* Clean up everything else. */
288+ xmlFreeParserCtxt (msr -> xml -> parsing_ctx );
289+ msr -> xml -> parsing_ctx = NULL ;
290+ msr_log (msr , 4 , "XML: Parsing complete (well_formed %u)." , msr -> xml -> well_formed );
129291
130- if (msr -> xml -> well_formed != 1 ) {
131- * error_msg = apr_psprintf (msr -> mp , "XML: Failed parsing document." );
132- return -1 ;
292+ if (msr -> xml -> well_formed != 1 ) {
293+ * error_msg = apr_psprintf (msr -> mp , "XML: Failed parsing document." );
294+ return -1 ;
295+ }
296+ }
297+
298+ if (msr -> txcfg -> parse_xml_into_args != MSC_XML_ARGS_OFF ) {
299+ if (xmlParseChunk (msr -> xml -> parsing_ctx_arg , NULL , 0 , 1 ) != 0 ) {
300+ if (msr -> xml -> xml_error ) {
301+ * error_msg = msr -> xml -> xml_error ;
302+ }
303+ else {
304+ * error_msg = apr_psprintf (msr -> mp , "XML: Failed parsing document for ARGS." );
305+ }
306+ xmlFreeParserCtxt (msr -> xml -> parsing_ctx_arg );
307+ msr -> xml -> parsing_ctx_arg = NULL ;
308+ return -1 ;
309+ }
310+ xmlFreeParserCtxt (msr -> xml -> parsing_ctx_arg );
311+ msr -> xml -> parsing_ctx_arg = NULL ;
133312 }
313+
134314 }
135315
136316 return 1 ;
@@ -152,6 +332,15 @@ apr_status_t xml_cleanup(modsec_rec *msr) {
152332 xmlFreeParserCtxt (msr -> xml -> parsing_ctx );
153333 msr -> xml -> parsing_ctx = NULL ;
154334 }
335+ if (msr -> xml -> parsing_ctx_arg != NULL ) {
336+
337+ if (msr -> xml -> parsing_ctx_arg -> myDoc ) {
338+ xmlFreeDoc (msr -> xml -> parsing_ctx_arg -> myDoc );
339+ }
340+
341+ xmlFreeParserCtxt (msr -> xml -> parsing_ctx_arg );
342+ msr -> xml -> parsing_ctx_arg = NULL ;
343+ }
155344 if (msr -> xml -> doc != NULL ) {
156345 xmlFreeDoc (msr -> xml -> doc );
157346 msr -> xml -> doc = NULL ;
0 commit comments