1313 *
1414 */
1515
16+ #ifdef WIN32
17+ #ifdef max
18+ #undef max
19+ #endif
20+ #ifdef min
21+ #undef min
22+ #endif
23+ #endif
1624
1725#ifdef __cplusplus
1826#include < ctime>
2230#include < list>
2331#include < set>
2432#include < cstring>
33+ #include < limits>
34+ #include < cstdint>
2535#endif
2636
2737
@@ -68,46 +78,132 @@ class Driver;
6878using modsecurity::debug_log::DebugLog;
6979using modsecurity::audit_log::AuditLog;
7080
71- /* * @ingroup ModSecurity_CPP_API */
72- class ConfigInt {
73- public:
74- ConfigInt () : m_set( false ), m_value( 0 ) { }
75- bool m_set;
76- int m_value;
81+ // template for different numeric int types
82+ template < typename T>
83+ class ConfigValue {
84+ public:
85+ bool m_set = false ;
86+ T m_value = 0 ;
7787
78- void merge (const ConfigInt *from) {
79- if (m_set == true || from->m_set == false ) {
88+ ConfigValue () = default ;
89+
90+ void merge (const ConfigValue<T>* from) {
91+ if (m_set || !from->m_set ) {
8092 return ;
8193 }
8294 m_set = true ;
8395 m_value = from->m_value ;
84- return ;
8596 }
86- };
8797
98+ // default parser
99+ bool parse (const std::string& a, std::string* errmsg = nullptr ) {
88100
89- class ConfigDouble {
90- public:
91- ConfigDouble () : m_set(false ), m_value(0 ) { }
92- bool m_set;
93- double m_value;
101+ // use an alias type because the template can convert both signed and unsigned int
102+ using LimitSigned = std::conditional_t <std::is_signed_v<T>, std::int64_t , std::uint64_t >;
103+ LimitSigned val;
94104
95- void merge (const ConfigDouble *from) {
96- if (m_set == true || from->m_set == false ) {
97- return ;
105+ // clear errno variable, wee need that later
106+ errno = 0 ;
107+
108+ try {
109+ if constexpr (std::is_signed_v<T>) {
110+ val = static_cast <std::int64_t >(std::stoll (a));
111+ } else {
112+ val = static_cast <std::uint64_t >(std::stoull (a));
113+ }
114+ }
115+ catch (const std::invalid_argument&) {
116+ // probably can't occur, but we handle it anyway
117+ set_error (errmsg, " Invalid number format (not numeric)" );
118+ return false ;
119+ }
120+ catch (const std::out_of_range&) {
121+ // the value is out of range, we can not handle it
122+ set_error (errmsg, " Number out of range" );
123+ return false ;
124+ }
125+ catch (...) { // NOSONAR
126+ // we don't need to handle all exceptions, the engine's BISON parser
127+ // does not allow other symbols than numbers
128+ set_error (errmsg, " An unknown error occurred while parsing number." );
129+ return false ;
130+ }
131+
132+ if (
133+ // The first condition will be true when the value is bigger than int64/uint64 maximum value.
134+ // The second condition checks whether the value fits into int64/uint64, but not
135+ // into the designed type, e.g., uint32; in that case the errno will be 0, but
136+ // we must check the value is not bigger than the defined maximum of the class.
137+ (errno == ERANGE && val == std::numeric_limits<LimitSigned>::max ())
138+ ||
139+ (val > static_cast <LimitSigned>(maxValue ()))
140+ ) {
141+ set_error (errmsg, " Value is too big." );
142+ return false ;
143+ }
144+
145+ if (
146+ // same as above
147+ (errno == ERANGE && val == std::numeric_limits<LimitSigned>::min ())
148+ ||
149+ (val < static_cast <LimitSigned>(minValue ()))
150+ ) {
151+ set_error (errmsg, " Value is too small." );
152+ return false ;
98153 }
154+
155+ m_value = static_cast <T>(val);
99156 m_set = true ;
100- m_value = from->m_value ;
101- return ;
157+ return true ;
158+
159+ }
160+
161+ protected:
162+ // derived classes must implement the maxValue
163+ virtual T maxValue () const = 0;
164+ // minValue is optional
165+ virtual T minValue () const { return 0 ; }
166+
167+ private:
168+ static inline void set_error (std::string* err, const char * msg) {
169+ if (err) {
170+ *err = msg;
171+ }
172+ }
173+ };
174+
175+ /* * @ingroup ModSecurity_CPP_API */
176+
177+ class ConfigInt : public ConfigValue <int32_t > {
178+ protected:
179+ int32_t minValue () const override {
180+ return std::numeric_limits<int32_t >::min ();
181+ }
182+ int32_t maxValue () const override {
183+ return std::numeric_limits<int32_t >::max ();
184+ }
185+ };
186+
187+ class ConfigUnsignedInt : public ConfigValue <uint32_t > {
188+ protected:
189+ uint32_t maxValue () const override {
190+ return std::numeric_limits<uint32_t >::max ();
191+ }
192+ };
193+
194+ class ConfigUnsignedLong : public ConfigValue <uint64_t > {
195+ protected:
196+ uint64_t maxValue () const override {
197+ return std::numeric_limits<uint64_t >::max ();
102198 }
103199};
104200
105201
106202class ConfigString {
107203 public:
108- ConfigString () : m_set( false ), m_value( " " ) { }
109- bool m_set ;
110- std::string m_value ;
204+ bool m_set = false ;
205+ std::string m_value = " " ;
206+ ConfigString () = default ;
111207
112208 void merge (const ConfigString *from) {
113209 if (m_set == true || from->m_set == false ) {
@@ -122,10 +218,10 @@ class ConfigString {
122218
123219class ConfigSet {
124220 public:
125- ConfigSet () : m_set(false ), m_clear(false ) { }
126- bool m_set;
127- bool m_clear;
221+ bool m_set = false ;
222+ bool m_clear = false ;
128223 std::set<std::string> m_value;
224+ ConfigSet () = default ;
129225};
130226
131227
@@ -504,14 +600,14 @@ class RulesSetProperties {
504600 ConfigXMLParseXmlIntoArgs m_secXMLParseXmlIntoArgs;
505601 ConfigBoolean m_tmpSaveUploadedFiles;
506602 ConfigBoolean m_uploadKeepFiles;
507- ConfigDouble m_argumentsLimit;
508- ConfigDouble m_requestBodyJsonDepthLimit;
509- ConfigDouble m_requestBodyLimit;
510- ConfigDouble m_requestBodyNoFilesLimit;
511- ConfigDouble m_responseBodyLimit;
512- ConfigInt m_pcreMatchLimit;
513- ConfigInt m_uploadFileLimit;
514- ConfigInt m_uploadFileMode;
603+ ConfigUnsignedInt m_argumentsLimit;
604+ ConfigUnsignedInt m_requestBodyJsonDepthLimit;
605+ ConfigUnsignedLong m_requestBodyLimit;
606+ ConfigUnsignedLong m_requestBodyNoFilesLimit;
607+ ConfigUnsignedLong m_responseBodyLimit;
608+ ConfigUnsignedInt m_pcreMatchLimit;
609+ ConfigUnsignedInt m_uploadFileLimit;
610+ ConfigUnsignedInt m_uploadFileMode;
515611 DebugLog *m_debugLog;
516612 OnFailedRemoteRulesAction m_remoteRulesActionOnFailed;
517613 RuleEngine m_secRuleEngine;
0 commit comments