1 /*
2  * ModSecurity, http://www.modsecurity.org/
3  * Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
4  *
5  * You may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * If any of the files related to licensing are missing or if you have any
11  * other questions related to licensing please contact Trustwave Holdings, Inc.
12  * directly using the email address security@modsecurity.org.
13  *
14  */
15 
16 #include "src/operators/validate_schema.h"
17 
18 #include <string>
19 
20 #include "src/operators/operator.h"
21 #include "src/request_body_processor/xml.h"
22 #include "src/utils/system.h"
23 
24 
25 namespace modsecurity {
26 namespace operators {
27 
28 #ifdef WITH_LIBXML2
29 
init(const std::string & file,std::string * error)30 bool ValidateSchema::init(const std::string &file, std::string *error) {
31     std::string err;
32     m_resource = utils::find_resource(m_param, file, &err);
33     if (m_resource == "") {
34         error->assign("XML: File not found: " + m_param + ". " + err);
35         return false;
36     }
37 
38     return true;
39 }
40 
41 
evaluate(Transaction * t,const std::string & str)42 bool ValidateSchema::evaluate(Transaction *t,
43     const std::string &str) {
44     int rc;
45 
46     m_parserCtx = xmlSchemaNewParserCtxt(m_resource.c_str());
47     if (m_parserCtx == NULL) {
48         std::stringstream err;
49         err << "XML: Failed to load Schema from file: ";
50         err << m_resource;
51         err << ". ";
52         if (m_err.empty() == false) {
53             err << m_err;
54         }
55         ms_dbg_a(t, 4, err.str());
56         return true;
57     }
58 
59     xmlSchemaSetParserErrors(m_parserCtx,
60         (xmlSchemaValidityErrorFunc)error_load,
61         (xmlSchemaValidityWarningFunc)warn_load, &m_err);
62 
63     xmlThrDefSetGenericErrorFunc(m_parserCtx,
64         null_error);
65 
66     xmlSetGenericErrorFunc(m_parserCtx,
67         null_error);
68 
69     m_schema = xmlSchemaParse(m_parserCtx);
70     if (m_schema == NULL) {
71         std::stringstream err;
72         err << "XML: Failed to load Schema: ";
73         err << m_resource;
74         err << ".";
75         if (m_err.empty() == false) {
76             err << " " << m_err;
77         }
78         ms_dbg_a(t, 4, err.str());
79         xmlSchemaFreeParserCtxt(m_parserCtx);
80         return true;
81     }
82 
83     m_validCtx = xmlSchemaNewValidCtxt(m_schema);
84     if (m_validCtx == NULL) {
85         std::stringstream err("XML: Failed to create validation context.");
86         if (m_err.empty() == false) {
87             err << " " << m_err;
88         }
89         ms_dbg_a(t, 4, err.str());
90         return true;
91     }
92 
93     /* Send validator errors/warnings to msr_log */
94     xmlSchemaSetValidErrors(m_validCtx,
95         (xmlSchemaValidityErrorFunc)error_runtime,
96         (xmlSchemaValidityWarningFunc)warn_runtime, t);
97 
98     if (t->m_xml->m_data.doc == NULL) {
99         ms_dbg_a(t, 4, "XML document tree could not be found for " \
100             "schema validation.");
101         return true;
102     }
103 
104     if (t->m_xml->m_data.well_formed != 1) {
105         ms_dbg_a(t, 4, "XML: Schema validation failed because " \
106             "content is not well formed.");
107         return true;
108     }
109 
110     /* Make sure there were no other generic processing errors */
111     /*
112     if (msr->msc_reqbody_error) {
113         ms_dbg_a(t, 4, "XML: Schema validation could not proceed due to previous"
114                 " processing errors.");
115         return true;
116     }
117     */
118 
119     rc = xmlSchemaValidateDoc(m_validCtx, t->m_xml->m_data.doc);
120     if (rc != 0) {
121         ms_dbg_a(t, 4, "XML: Schema validation failed.");
122         xmlSchemaFree(m_schema);
123         xmlSchemaFreeParserCtxt(m_parserCtx);
124         return true; /* No match. */
125     }
126 
127     ms_dbg_a(t, 4, "XML: Successfully validated payload against " \
128         "Schema: " + m_resource);
129     xmlSchemaFree(m_schema);
130     xmlSchemaFreeParserCtxt(m_parserCtx);
131 
132     return false;
133 }
134 
135 #endif
136 
137 }  // namespace operators
138 }  // namespace modsecurity
139