diff --git a/headers/modsecurity/debug_log.h b/headers/modsecurity/debug_log.h index 8455af74..06da831f 100644 --- a/headers/modsecurity/debug_log.h +++ b/headers/modsecurity/debug_log.h @@ -14,8 +14,6 @@ */ #ifdef __cplusplus -#include -#include #include #endif @@ -32,39 +30,25 @@ typedef struct DebugLog_t DebugLog; namespace ModSecurity { /** @ingroup ModSecurity_CPP_API */ -class DebugLog : public std::ofstream { +class DebugLog { public: - /* - static ModSecurityDebugLog& instance() { - static ModSecurityDebugLog i; - return i; - } - */ DebugLog() - : m_is_configured(false), - m_debug_level(0), - m_referenceCount(0) { } + : m_debugLevel(-1), + m_fileName("") { } - bool setOutputFile(const std::string& file); - virtual bool write_log(int level, const std::string& data); - bool setDebugLevel(int level); - bool isConfigured(); + ~DebugLog(); - - - virtual DebugLog *new_instance(); - - void refCountDecreaseAndCheck(void); - void refCountIncrease(void); + virtual void write(int level, const std::string &msg); + bool isLogFileSet(); + bool isLogLevelSet(); + void setDebugLogLevel(int level); + void setDebugLogFile(const std::string &fileName); + const std::string& getDebugLogFile(); + int getDebugLogLevel(); private: - /* - ModSecurityDebugLog(ModSecurityDebugLog const&); - void operator=(ModSecurityDebugLog const&); - */ - int m_debug_level; - bool m_is_configured; - int m_referenceCount; + int m_debugLevel; + std::string m_fileName; }; } // namespace ModSecurity diff --git a/headers/modsecurity/rules.h b/headers/modsecurity/rules.h index b059f9d3..075534ae 100644 --- a/headers/modsecurity/rules.h +++ b/headers/modsecurity/rules.h @@ -45,8 +45,7 @@ class Driver; class Rules : public RulesProperties { public: Rules() - : debugLog(NULL), - RulesProperties(NULL), + : RulesProperties(new DebugLog()), m_referenceCount(0), unicode_codepage(0) { unicode_map_table = reinterpret_cast( @@ -55,8 +54,7 @@ class Rules : public RulesProperties { } explicit Rules(DebugLog *customLog) - : debugLog(NULL), - m_referenceCount(0), + : m_referenceCount(0), unicode_codepage(0), RulesProperties(customLog) { unicode_map_table = reinterpret_cast( @@ -86,7 +84,6 @@ class Rules : public RulesProperties { std::ostringstream parserError; - DebugLog *debugLog; int *unicode_map_table; int64_t unicode_codepage; diff --git a/headers/modsecurity/rules_properties.h b/headers/modsecurity/rules_properties.h index e80daf88..c50799a8 100644 --- a/headers/modsecurity/rules_properties.h +++ b/headers/modsecurity/rules_properties.h @@ -42,7 +42,7 @@ class RulesProperties { public: RulesProperties() : audit_log(NULL), - customDebugLog(NULL), + m_debugLog(new DebugLog()), remoteRulesActionOnFailed(AbortOnFailedRemoteRulesAction), requestBodyLimit(0), requestBodyNoFilesLimit(0), @@ -51,26 +51,25 @@ class RulesProperties { secResponseBodyAccess(false), requestBodyLimitAction(ProcessPartialBodyLimitAction), responseBodyLimit(0), - debugLevel(0), responseBodyLimitAction(ProcessPartialBodyLimitAction), secRuleEngine(DetectionOnlyRuleEngine) { } - explicit RulesProperties(DebugLog *customDebugLog) + explicit RulesProperties(DebugLog *debugLog) : audit_log(NULL), - customDebugLog(customDebugLog), + m_debugLog(debugLog), remoteRulesActionOnFailed(AbortOnFailedRemoteRulesAction), - secRequestBodyAccess(false), - secResponseBodyAccess(false), - debugLevel(0), requestBodyLimit(0), - requestBodyLimitAction(ProcessPartialBodyLimitAction), requestBodyNoFilesLimit(0), requestBodyInMemoryLimit(0), + secRequestBodyAccess(false), + secResponseBodyAccess(false), + requestBodyLimitAction(ProcessPartialBodyLimitAction), responseBodyLimit(0), responseBodyLimitAction(ProcessPartialBodyLimitAction), secRuleEngine(DetectionOnlyRuleEngine) { } - - ~RulesProperties() { } + ~RulesProperties() { + delete m_debugLog; + } std::vector rules[7]; // ModSecurity::Phases::NUMBER_OF_PHASES @@ -167,16 +166,13 @@ class RulesProperties { BodyLimitAction requestBodyLimitAction; BodyLimitAction responseBodyLimitAction; - DebugLog *customDebugLog; - bool secRequestBodyAccess; bool secResponseBodyAccess; std::string audit_log_path; std::string audit_log_parts; - std::string debug_log_path; - int debugLevel; std::list components; + DebugLog *m_debugLog; std::ostringstream parserError; diff --git a/src/Makefile.am b/src/Makefile.am index 870eda82..c5feab08 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -169,6 +169,8 @@ libmodsecurity_la_SOURCES = \ rules.cc \ utils.cc \ debug_log.cc \ + debug_log_writer.cc \ + debug_log_writer_agent.cc \ macro_expansion.cc \ request_body_processor/multipart.cc \ request_body_processor/multipart_blob.cc \ diff --git a/src/debug_log.cc b/src/debug_log.cc index e8b0647e..9484fdf0 100644 --- a/src/debug_log.cc +++ b/src/debug_log.cc @@ -19,122 +19,60 @@ #include +#include "src/debug_log_writer.h" +#include "src/debug_log_writer_agent.h" + namespace ModSecurity { - -/** - * @name new_instance - * @brief Create a new instance of the DebugLog. - * - * @return Debug log pointer - * @retval >0 Debug log structure was initialized correctly - * @retval NULL Debug log could not be initialized. - * - */ -DebugLog *DebugLog::new_instance() { - return new DebugLog(); +DebugLog::~DebugLog() { + DebugLogWriter::getInstance().close(m_fileName); } -/** - * @name setOutputFile - * @brief Set an output file where the log will be saved - * - * @param file_path Path to the log file. - * - * @return If the operation successful or not. - * @retval true Operation was successful. - * @retval false Operation failed. - * - */ -bool DebugLog::setOutputFile(const std::string& file_path) { - if (is_open()) { - close(); +void DebugLog::setDebugLogFile(const std::string& fileName) { + m_fileName = fileName; + if (isLogFileSet()) { + DebugLogWriter::getInstance().close(m_fileName); } - open(file_path, std::fstream::out | std::fstream::app); - - if (!is_open()) { - return false; - } - - return true; + DebugLogWriter::getInstance().open(m_fileName); } -/** - * @name write_log - * @brief Write a message into the debug log. - * - * @param debug_level Debug level of the given message. - * @param text Message to be written. - * - * @return If the operation successful or not. - * @retval true Operation was successful. - * @retval false Operation failed. - * - */ -bool DebugLog::write_log(int debug_level, const std::string &text) { - std::cout << "?" << std::to_string(is_open()) << ":" << std::to_string(m_debug_level) <<" [" << debug_level << "] " << text << std::endl; - if (!is_open()) { - return false; - } - - if (debug_level <= m_debug_level) { - *this << "[" << debug_level << "] " << text << std::endl; - } - - return true; +void DebugLog::setDebugLogLevel(int level) { + m_debugLevel = level; } -/** - * @name setDebugLevel - * @brief Changes the default debug level. - * - * @param level Debug level. - * - * @return If the operation successful or not. - * @retval true Operation was successful. - * @retval false Operation failed. - * - */ -bool DebugLog::setDebugLevel(int level) { - if (level < 0 || level > 9) { - return false; +bool DebugLog::isLogFileSet() { + return m_fileName.empty() == false; +} + + +bool DebugLog::isLogLevelSet() { + return m_debugLevel != -1; +} + + +const std::string& DebugLog::getDebugLogFile() { + return m_fileName; +} + + +int DebugLog::getDebugLogLevel() { + if (m_debugLevel < 0) { + return 0; } - m_debug_level = level; - - return true; + return m_debugLevel; } -/** - * @name isConfigured - * @brief Returns if debug log is configured or not. - * - * @return If the debug log is configured or not - * @retval true It is configured. - * @retval false It is not configured. - * - */ -bool DebugLog::isConfigured() { - return m_is_configured; -} - - -void DebugLog::refCountDecreaseAndCheck(void) { - this->m_referenceCount--; - if (this->m_referenceCount == 0) { - delete this; +void DebugLog::write(int level, const std::string &msg) { + if (level <= m_debugLevel) { + DebugLogWriter::getInstance().write(m_fileName, "[" + std::to_string(level) + "] " + msg); } } -void DebugLog::refCountIncrease(void) { - this->m_referenceCount++; -} - - -} // namespace ModSecurity +} // namespace ModSecurity \ No newline at end of file diff --git a/src/debug_log_writer.cc b/src/debug_log_writer.cc new file mode 100644 index 00000000..ecc7c07d --- /dev/null +++ b/src/debug_log_writer.cc @@ -0,0 +1,72 @@ +/* + * ModSecurity, http://www.modsecurity.org/ + * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/) + * + * You may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Trustwave Holdings, Inc. + * directly using the email address security@modsecurity.org. + * + */ + +#include "src/debug_log_writer.h" + +#include + +#include + +#include "src/debug_log_writer_agent.h" + +namespace ModSecurity { + + +void DebugLogWriter::open(const std::string& fileName) { + std::map::iterator it; + DebugLogWriterAgent *agent; + + it = agents.find(fileName); + if (it != agents.end()) { + agent = it->second; + } else { + agent = new DebugLogWriterAgent(fileName); + agents[fileName] = agent; + } + agent->refCountIncrease(); +} + + +void DebugLogWriter::close(const std::string& fileName) { +#if 0 + std::map::iterator it; + DebugLogWriterAgent *agent; + it = agents.find(fileName); + if (it != agents.end()) { + agent = it->second; + if (agent->refCountDecreaseAndCheck()) { + agents.erase(it); + } + } +#endif +} + + +void DebugLogWriter::write(const std::string& file, const std::string &msg) { + std::map::iterator it; + DebugLogWriterAgent *agent; + + it = agents.find(file); + if (it != agents.end()) { + agent = it->second; + agent->write(msg); + } else { + std::cout << file << ": " << msg << std::endl; + } +} + + +} // namespace ModSecurity + diff --git a/src/debug_log_writer.h b/src/debug_log_writer.h new file mode 100644 index 00000000..7c41d88b --- /dev/null +++ b/src/debug_log_writer.h @@ -0,0 +1,57 @@ +/* + * ModSecurity, http://www.modsecurity.org/ + * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/) + * + * You may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Trustwave Holdings, Inc. + * directly using the email address security@modsecurity.org. + * + */ + +#include +#include +#include + +#ifndef SRC_DEBUG_LOG_WRITER_H_ +#define SRC_DEBUG_LOG_WRITER_H_ + +#include "debug_log_writer_agent.h" + + +namespace ModSecurity { + +/** @ingroup ModSecurity_CPP_API */ +class DebugLogWriter { + public: + static DebugLogWriter& getInstance() { + static DebugLogWriter instance; + return instance; + } + + void write(const std::string& file, const std::string& msg); + void close(const std::string& m_fileName); + void open(const std::string& m_fileName); + private: + DebugLogWriter() {}; + + // C++ 03 + // ======== + // Dont forget to declare these two. You want to make sure they + // are unacceptable otherwise you may accidentally get copies of + // your singleton appearing. + DebugLogWriter(DebugLogWriter const&); + void operator=(DebugLogWriter const&); + + + std::map agents; +}; + + +} // namespace ModSecurity + +#endif // SRC_DEBUG_LOG_WRITER_H_ diff --git a/src/debug_log_writer_agent.cc b/src/debug_log_writer_agent.cc new file mode 100644 index 00000000..1eb68d6f --- /dev/null +++ b/src/debug_log_writer_agent.cc @@ -0,0 +1,46 @@ +/* + * ModSecurity, http://www.modsecurity.org/ + * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/) + * + * You may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Trustwave Holdings, Inc. + * directly using the email address security@modsecurity.org. + * + */ + +#include "src/debug_log_writer_agent.h" + +#include + +#include + +#include "debug_log_writer.h" + + + +namespace ModSecurity { + + +DebugLogWriterAgent::DebugLogWriterAgent(const std::string& fileName) : + m_referenceCount(0), + m_fileName(fileName) { + open(m_fileName, std::fstream::out | std::fstream::app); +} + +void DebugLogWriterAgent::write(const std::string& msg) { + if (!is_open()) { + std::cout << "Agent: " << m_fileName << ": " << msg << std::endl; + return; + } + + *this << msg << std::endl; + *this << flush(); +} + + +} // namespace ModSecurity \ No newline at end of file diff --git a/src/debug_log_writer_agent.h b/src/debug_log_writer_agent.h new file mode 100644 index 00000000..a6a86fb2 --- /dev/null +++ b/src/debug_log_writer_agent.h @@ -0,0 +1,56 @@ +/* + * ModSecurity, http://www.modsecurity.org/ + * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/) + * + * You may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Trustwave Holdings, Inc. + * directly using the email address security@modsecurity.org. + * + */ + +#include +#include +#include + +#ifndef SRC_DEBUG_LOG_WRITER_AGENT_H_ +#define SRC_DEBUG_LOG_WRITER_AGENT_H_ + +namespace ModSecurity { + +/** @ingroup ModSecurity_CPP_API */ +class DebugLogWriterAgent : public std::ofstream { + public: + DebugLogWriterAgent(const std::string& fileName); + ~DebugLogWriterAgent() { + if (is_open()) { + close(); + } + } + + void write(const std::string& msg); + bool refCountDecreaseAndCheck() { + this->m_referenceCount--; + if (this->m_referenceCount == 0) { + delete this; + return true; + } + return false; + } + + void refCountIncrease() { + this->m_referenceCount++; + } + + int m_referenceCount; + std::string m_fileName; +}; + + +} // namespace ModSecurity + +#endif // SRC_DEBUG_LOG_WRITER_AGENT_H_ diff --git a/src/parser/seclang-parser.yy b/src/parser/seclang-parser.yy index 2e659b2e..72328514 100644 --- a/src/parser/seclang-parser.yy +++ b/src/parser/seclang-parser.yy @@ -373,11 +373,23 @@ expression: /* Debug log: start */ | CONFIG_DIR_DEBUG_LVL { - driver.debugLevel = atoi($1.c_str()); + if (driver.m_debugLog != NULL) { + driver.m_debugLog->setDebugLogLevel(atoi($1.c_str())); + } else { + driver.parserError << "Internal error, there is no DebugLog "; + driver.parserError << "object associated with the driver class"; + YYERROR; + } } | CONFIG_DIR_DEBUG_LOG { - driver.debug_log_path = $1; + if (driver.m_debugLog != NULL) { + driver.m_debugLog->setDebugLogFile($1); + } else { + driver.parserError << "Internal error, there is no DebugLog "; + driver.parserError << "object associated with the driver class"; + YYERROR; + } } /* Debug log: end */ | CONFIG_DIR_GEO_DB diff --git a/src/rules.cc b/src/rules.cc index 5d9d15e0..7f0a92f8 100644 --- a/src/rules.cc +++ b/src/rules.cc @@ -91,10 +91,6 @@ Rules::~Rules() { if (audit_log) { audit_log->refCountDecreaseAndCheck(); } - /** Cleanup debug log */ - if (debugLog) { - debugLog->refCountDecreaseAndCheck(); - } } @@ -197,27 +193,25 @@ int Rules::merge(Driver *from) { this->secRuleEngine = from->secRuleEngine; this->secRequestBodyAccess = from->secRequestBodyAccess; this->secResponseBodyAccess = from->secResponseBodyAccess; - this->debug_log_path = from->debug_log_path; - this->debugLevel = from->debugLevel; + if (from->m_debugLog && this->m_debugLog && + from->m_debugLog->isLogFileSet()) { + this->m_debugLog->setDebugLogFile(from->m_debugLog->getDebugLogFile()); + } + if (from->m_debugLog && this->m_debugLog && + from->m_debugLog->isLogLevelSet()) { + this->m_debugLog->setDebugLogLevel( + from->m_debugLog->getDebugLogLevel()); + } this->components = from->components; this->requestBodyLimit = from->requestBodyLimit; this->responseBodyLimit = from->responseBodyLimit; this->requestBodyLimitAction = from->requestBodyLimitAction; this->responseBodyLimitAction = from->responseBodyLimitAction; - if (customDebugLog) { - this->debugLog = customDebugLog->new_instance(); - } else { - this->debugLog = new DebugLog(); - } - this->debugLog->refCountIncrease(); this->audit_log = from->audit_log; this->audit_log->refCountIncrease(); - this->debugLog->setDebugLevel(from->debugLevel); - this->debugLog->setOutputFile(from->debug_log_path); - return amount_of_rules; } @@ -243,28 +237,28 @@ int Rules::merge(Rules *from) { this->requestBodyLimitAction = from->requestBodyLimitAction; this->responseBodyLimitAction = from->responseBodyLimitAction; - if (customDebugLog) { - this->debugLog = customDebugLog->new_instance(); - } else { - this->debugLog = new DebugLog(); + if (from->m_debugLog && this->m_debugLog && + from->m_debugLog->isLogFileSet()) { + this->m_debugLog->setDebugLogFile(from->m_debugLog->getDebugLogFile()); + } + if (from->m_debugLog && this->m_debugLog && + from->m_debugLog->isLogLevelSet()) { + this->m_debugLog->setDebugLogLevel( + from->m_debugLog->getDebugLogLevel()); } - this->debugLog->refCountIncrease(); this->audit_log = from->audit_log; if (this->audit_log != NULL) { this->audit_log->refCountIncrease(); } - this->debugLog->setDebugLevel(from->debugLevel); - this->debugLog->setOutputFile(from->debug_log_path); - return amount_of_rules; } void Rules::debug(int level, std::string message) { - if (debugLog != NULL) { - debugLog->write_log(level, message); + if (m_debugLog != NULL) { + m_debugLog->write(level, message); } } diff --git a/test/regression/custom_debug_log.cc b/test/regression/custom_debug_log.cc index 8fca802b..d904a5fd 100644 --- a/test/regression/custom_debug_log.cc +++ b/test/regression/custom_debug_log.cc @@ -28,9 +28,8 @@ CustomDebugLog *CustomDebugLog::new_instance() { } -bool CustomDebugLog::write_log(int level, const std::string& message) { +void CustomDebugLog::write(int level, const std::string& message) { m_log << "[" << level << "] " << message << std::endl; - return true; } diff --git a/test/regression/custom_debug_log.h b/test/regression/custom_debug_log.h index 0d8f05cf..c7a8c404 100644 --- a/test/regression/custom_debug_log.h +++ b/test/regression/custom_debug_log.h @@ -27,7 +27,7 @@ class CustomDebugLog : public ModSecurity::DebugLog { public: CustomDebugLog *new_instance(); - bool write_log(int level, const std::string& message) override; + void write(int level, const std::string& message) override; bool contains(const std::string& pattern); std::string log_messages(); diff --git a/test/regression/regression.cc b/test/regression/regression.cc index dc9409a8..671085cd 100644 --- a/test/regression/regression.cc +++ b/test/regression/regression.cc @@ -191,7 +191,7 @@ end: modsec_assay->processLogging(r.status); CustomDebugLog *d = reinterpret_cast - (modsec_rules->debugLog); + (modsec_rules->m_debugLog); if (d != NULL) { if (!d->contains(t->debug_log)) { @@ -220,7 +220,7 @@ after_debug_log: delete modsec_assay; delete modsec_rules; delete modsec; - delete debug_log; + /* delete debug_log; */ res->insert(res->end(), r.begin(), r.end()); }