diff --git a/headers/modsecurity/collection/collection.h b/headers/modsecurity/collection/collection.h new file mode 100644 index 00000000..04159e20 --- /dev/null +++ b/headers/modsecurity/collection/collection.h @@ -0,0 +1,66 @@ +/* + * 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. + * + */ + + +#ifdef __cplusplus +#include +#include +#include +#include +#include +#include +#endif + + +#include "modsecurity/collection/variable.h" + +#ifndef HEADERS_MODSECURITY_TRANSACTION_COLLECTION_H_ +#define HEADERS_MODSECURITY_TRANSACTION_COLLECTION_H_ + +#ifndef __cplusplus +typedef struct Variable_t Variables; +#endif + +#ifdef __cplusplus +namespace modsecurity { +namespace collection { + +class Collection { + public: + virtual void store(std::string key, std::string value) = 0; + + virtual bool storeOrUpdateFirst(const std::string &key, + const std::string &value) = 0; + + virtual bool updateFirst(const std::string &key, const std::string &value) = 0; + + virtual void del(const std::string& key) = 0; + + virtual std::string* resolveFirst(const std::string& var) = 0; + + virtual void resolveSingleMatch(const std::string& var, + std::vector *l) = 0; + virtual void resolveMultiMatches(const std::string& var, + std::vector *l) = 0; + virtual void resolveRegularExpression(const std::string& var, + std::vector *l) = 0; +}; + +} // namespace collection +} // namespace modsecurity +#endif + + +#endif // HEADERS_MODSECURITY_TRANSACTION_COLLECTION_H_ diff --git a/headers/modsecurity/collection/collections.h b/headers/modsecurity/collection/collections.h new file mode 100644 index 00000000..bbaad40f --- /dev/null +++ b/headers/modsecurity/collection/collections.h @@ -0,0 +1,102 @@ +/* + * 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. + * + */ + + +#ifdef __cplusplus +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "modsecurity/collection/global_collection.h" +#include "modsecurity/collection/collection.h" +#include "modsecurity/collection/variable.h" + +#ifndef HEADERS_MODSECURITY_TRANSACTION_COLLECTIONS_H_ +#define HEADERS_MODSECURITY_TRANSACTION_COLLECTIONS_H_ + +#ifndef __cplusplus +typedef struct Collections_t Collections; +#endif + +#ifdef __cplusplus + +namespace modsecurity { +namespace collection { + +class Collections : + public std::unordered_map { + public: + Collections(GlobalCollection *global, GlobalCollection *ip); + ~Collections(); + + void store(std::string key, std::string value); + void storeOrUpdateFirst(const std::string& collectionName, + const std::string& variableName, + const std::string& targetValue); + bool storeOrUpdateFirst(const std::string &key, const std::string &value); + bool updateFirst(const std::string &key, const std::string &value); + void del(const std::string& key); + std::string* resolveFirst(const std::string& var); + std::string* resolveFirst(const std::string& collectionName, + const std::string& var); + + void resolveSingleMatch(const std::string& var, + std::vector *l); + void resolveSingleMatch(const std::string& var, + const std::string& collection, + std::vector *l); + void resolveMultiMatches(const std::string& var, + std::vector *l); + void resolveMultiMatches(const std::string& var, + const std::string& collection, + std::vector *l); + void resolveRegularExpression(const std::string& var, + std::vector *l); + void resolveRegularExpression(const std::string& var, + const std::string& collection, + std::vector *l); + + /** + * This is a special collection to host the transaction variables. + * + * It exists independent of initialization and it is only valid during a transaction. + * + * Notice that it is not the TX collection. + */ + Collection *m_transient; + + std::string m_global_collection_key; + std::string m_ip_collection_key; + + GlobalCollection *m_global_collection; + GlobalCollection *m_ip_collection; +}; + +} // namespace collection +} // namespace modsecurity +#endif + + +#endif // HEADERS_MODSECURITY_TRANSACTION_COLLECTIONS_H_ + + diff --git a/headers/modsecurity/collection/global_collection.h b/headers/modsecurity/collection/global_collection.h new file mode 100644 index 00000000..67624360 --- /dev/null +++ b/headers/modsecurity/collection/global_collection.h @@ -0,0 +1,119 @@ +/* + * 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. + * + */ + + +#ifdef __cplusplus +#include +#include +#include +#include +#include +#include +#endif + +#include "modsecurity/collection/collection.h" +#include "modsecurity/collection/variable.h" + + +#ifndef HEADERS_MODSECURITY_TRANSACTION_GLOBAL_COLLECTION_H_ +#define HEADERS_MODSECURITY_TRANSACTION_GLOBAL_COLLECTION_H_ + +#ifndef __cplusplus +typedef struct GlobalCollection_t GlobalCollection; +#endif + +#ifdef __cplusplus +namespace modsecurity { +namespace collection { + +class CollectionKey { + public: + CollectionKey() + : m_compartiment(""), + m_name("") { } + explicit CollectionKey(std::string name) + : m_compartiment(""), + m_name(name) { } + CollectionKey(std::string name, std::string compartiment) + : m_compartiment(compartiment), + m_name(name) { } + + std::string m_name; + std::string m_compartiment; +}; + + +class collection_hash { + public: + size_t operator()(const CollectionKey *v) const { + size_t h = 0; + std::for_each(v->m_name.begin(), v->m_name.end(), [&](char c) { + h += tolower(c); + }); + std::for_each(v->m_compartiment.begin(), + v->m_compartiment.end(), [&](char c) { + h += tolower(c); + }); + + return h; + } +}; + + +class collection_equal { + public: + bool operator()(const CollectionKey *u, const CollectionKey *v) const { + return u->m_name == v->m_name + && u->m_compartiment == v->m_compartiment; + } +}; + + +class GlobalCollection : + public std::unordered_multimap { + public: + GlobalCollection(); + ~GlobalCollection(); + void store(std::string key, std::string compartment, std::string value); + + bool storeOrUpdateFirst(const std::string &key, std::string compartment, + const std::string &value); + + bool updateFirst(const std::string &key, std::string compartment, + const std::string &value); + + void del(const std::string& key, std::string compartment); + + std::string* resolveFirst(const std::string& var, std::string compartment); + void resolveSingleMatch(const std::string& var, std::string compartment, + std::vector *l); + void resolveMultiMatches(const std::string& var, std::string compartment, + std::vector *l); + + void resolveRegularExpression(const std::string& var, + std::string compartment, + std::vector *l); +}; + +} // namespace collection +} // namespace modsecurity + +#endif + + +#endif // HEADERS_MODSECURITY_TRANSACTION_GLOBAL_COLLECTION_H_ + + diff --git a/headers/modsecurity/collection/variable.h b/headers/modsecurity/collection/variable.h new file mode 100644 index 00000000..6c2a0211 --- /dev/null +++ b/headers/modsecurity/collection/variable.h @@ -0,0 +1,47 @@ +/* + * 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. + * + */ + + +#ifdef __cplusplus +#include +#endif + + +#ifndef HEADERS_MODSECURITY_TRANSACTION_VARIABLE_H_ +#define HEADERS_MODSECURITY_TRANSACTION_VARIABLE_H_ + + +#ifndef __cplusplus +typedef struct Variable_t Variable; +#endif + +#ifdef __cplusplus +namespace modsecurity { +namespace collection { + +class Variable { + public: + Variable(const std::string& key, const std::string& value) : + m_key(key), + m_value(value) { } + std::string m_key; + std::string m_value; +}; + +} // namespace collection +} // namespace modsecurity +#endif + +#endif // HEADERS_MODSECURITY_TRANSACTION_VARIABLE_H_ diff --git a/src/Makefile.am b/src/Makefile.am index c54e584a..026a047b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -173,11 +173,13 @@ UTILS = \ utils/regex.cc \ utils/sha1.cc - -libmodsecurity_la_SOURCES = \ - collection/collection.cc \ +COLLECTION = \ collection/collections.cc \ collection/global_collections.cc \ + collection/backend/in_memory-per_process.cc + + +libmodsecurity_la_SOURCES = \ parser/seclang-parser.yy \ parser/seclang-scanner.ll \ parser/driver.cc \ @@ -199,6 +201,7 @@ libmodsecurity_la_SOURCES = \ rule.cc \ unique_id.cc \ ${ACTIONS} \ + ${COLLECTION} \ ${OPERATORS} \ ${UTILS} \ ${VARIABLES} diff --git a/src/collection/backend/in_memory-per_process.cc b/src/collection/backend/in_memory-per_process.cc new file mode 100644 index 00000000..4269e051 --- /dev/null +++ b/src/collection/backend/in_memory-per_process.cc @@ -0,0 +1,126 @@ +/* + * 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/collection/backend/in_memory-per_process.h" + +#ifdef __cplusplus +#include +#include +#include +#include +#endif + +#include "modsecurity/collection/variable.h" +#include "src/utils.h" + +namespace modsecurity { +namespace collection { +namespace backend { + + +InMemoryPerProcess::InMemoryPerProcess() { + this->reserve(1000); +} + +InMemoryPerProcess::~InMemoryPerProcess() { + this->clear(); +} + +void InMemoryPerProcess::store(std::string key, std::string value) { + this->emplace(key, value); +} + + +bool InMemoryPerProcess::storeOrUpdateFirst(const std::string &key, + const std::string &value) { + if (updateFirst(key, value) == false) { + store(key, value); + } + return true; +} + + +bool InMemoryPerProcess::updateFirst(const std::string &key, const std::string &value) { + auto range = this->equal_range(key); + + for (auto it = range.first; it != range.second; ++it) { + it->second = value; + return true; + } + return false; +} + + +void InMemoryPerProcess::del(const std::string& key) { + this->erase(key); +} + + +void InMemoryPerProcess::resolveSingleMatch(const std::string& var, + std::vector *l) { + auto range = this->equal_range(var); + + for (auto it = range.first; it != range.second; ++it) { + l->push_back(new Variable(var, it->second)); + } +} + + +void InMemoryPerProcess::resolveMultiMatches(const std::string& var, + std::vector *l) { + size_t keySize = var.size(); + l->reserve(15); + + auto range = this->equal_range(var); + + for (auto it = range.first; it != range.second; ++it) { + l->insert(l->begin(), new Variable(var, it->second)); + } + + for (const auto& x : *this) { + if (x.first.size() <= keySize + 1) { + continue; + } + if (x.first.at(keySize) != ':') { + continue; + } + if (x.first.compare(0, keySize, var) != 0) { + continue; + } + l->insert(l->begin(), new Variable(x.first, x.second)); + } +} + + +void InMemoryPerProcess::resolveRegularExpression(const std::string& var, + std::vector *l) { + /* Not ready */ +} + + +std::string* InMemoryPerProcess::resolveFirst(const std::string& var) { + auto range = equal_range(var); + + for (auto it = range.first; it != range.second; ++it) { + return &it->second; + } + + return NULL; +} + +} // namespace backend +} // namespace collection +} // namespace modsecurity diff --git a/src/collection/backend/in_memory-per_process.h b/src/collection/backend/in_memory-per_process.h new file mode 100644 index 00000000..d821b1b4 --- /dev/null +++ b/src/collection/backend/in_memory-per_process.h @@ -0,0 +1,103 @@ +/* + * 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. + * + */ + + +#ifdef __cplusplus +#include +#include +#include +#include +#include +#include +#endif + + +#include "modsecurity/collection/variable.h" +#include "modsecurity/collection/collection.h" + +#ifndef HEADERS_MODSECURITY_COLLECTION_BACKEND_IN_MEMORY_PER_PROCESS_H_ +#define HEADERS_MODSECURITY_COLLECTION_BACKEND_IN_MEMORY_PER_PROCESS_H_ + +#ifdef __cplusplus +namespace modsecurity { +namespace collection { +namespace backend { + +/* + * FIXME: + * + * This was an example grabbed from: + * http://stackoverflow.com/questions/8627698/case-insensitive-stl-containers-e-g-stdunordered-set + * + * We have to have a better hash function, maybe based on the std::hash. + * + */ +struct MyEqual { + bool operator()(const std::string& Left, const std::string& Right) const { + /* + return Left.size() == Right.size() + && std::equal(Left.begin(), Left.end(), Right.begin(), + [](char a, char b) { + return tolower(a) == tolower(b); + }); + */ + return Left == Right; + } +}; + +struct MyHash{ + size_t operator()(const std::string& Keyval) const { + // You might need a better hash function than this + size_t h = 0; + std::for_each(Keyval.begin(), Keyval.end(), [&](char c) { + h += c; + }); + return h; + } +}; + +class InMemoryPerProcess : + public std::unordered_multimap*/MyHash, MyEqual>, + public Collection { + public: + InMemoryPerProcess(); + ~InMemoryPerProcess(); + void store(std::string key, std::string value); + + bool storeOrUpdateFirst(const std::string &key, + const std::string &value); + + bool updateFirst(const std::string &key, const std::string &value); + + void del(const std::string& key); + + std::string* resolveFirst(const std::string& var); + + void resolveSingleMatch(const std::string& var, + std::vector *l); + void resolveMultiMatches(const std::string& var, + std::vector *l); + void resolveRegularExpression(const std::string& var, + std::vector *l); +}; + +} // namespace backend +} // namespace collection +} // namespace modsecurity +#endif + + +#endif // HEADERS_MODSECURITY_COLLECTION_BACKEND_IN_MEMORY_PER_PROCESS_H_ diff --git a/src/collection/collections.cc b/src/collection/collections.cc index 77309767..515233f7 100644 --- a/src/collection/collections.cc +++ b/src/collection/collections.cc @@ -26,6 +26,7 @@ #include "modsecurity/collection/variable.h" #include "modsecurity/collection/collection.h" +#include "src/collection/backend/in_memory-per_process.h" #include "src/utils.h" namespace modsecurity { @@ -37,9 +38,10 @@ Collections::Collections(GlobalCollection *global, : m_global_collection_key(""), m_ip_collection_key(""), m_global_collection(global), - m_ip_collection(ip) { + m_ip_collection(ip), + m_transient(new backend::InMemoryPerProcess()) { /* Create collection TX */ - this->emplace("TX", new Collection()); + this->emplace("TX", new backend::InMemoryPerProcess()); } @@ -82,38 +84,38 @@ void Collections::storeOrUpdateFirst(const std::string& collectionName, void Collections::store(std::string key, std::string value) { - m_transient.store(key, value); + m_transient->store(key, value); } bool Collections::storeOrUpdateFirst(const std::string &key, const std::string &value) { - return m_transient.storeOrUpdateFirst(key, value); + return m_transient->storeOrUpdateFirst(key, value); } bool Collections::updateFirst(const std::string &key, const std::string &value) { - return m_transient.updateFirst(key, value); + return m_transient->updateFirst(key, value); } void Collections::del(const std::string& key) { - return m_transient.del(key); + return m_transient->del(key); } std::string* Collections::resolveFirst(const std::string& var) { - std::string *transientVar = m_transient.resolveFirst(var); + std::string *transientVar = m_transient->resolveFirst(var); if (transientVar != NULL) { return transientVar; } for (auto &a : *this) { - auto range = a.second->equal_range(var); - for (auto it = range.first; it != range.second; ++it) { - return & it->second; + std::string *res = a.second->resolveFirst(toupper(a.first) + ":" + var); + if (res != NULL) { + return res; } } @@ -137,11 +139,9 @@ std::string* Collections::resolveFirst(const std::string& collectionName, for (auto &a : *this) { if (tolower(a.first) == tolower(collectionName)) { - Collection *t = a.second; - auto range = t->equal_range(toupper(collectionName) - + ":" + var); - for (auto it = range.first; it != range.second; ++it) { - return &it->second; + std::string *res = a.second->resolveFirst(toupper(a.first) + ":" + var); + if (res != NULL) { + return res; } } } @@ -153,7 +153,7 @@ std::string* Collections::resolveFirst(const std::string& collectionName, void Collections::resolveSingleMatch(const std::string& var, std::vector *l) { - m_transient.resolveSingleMatch(var, l); + m_transient->resolveSingleMatch(var, l); } @@ -182,7 +182,7 @@ void Collections::resolveSingleMatch(const std::string& var, void Collections::resolveMultiMatches(const std::string& var, std::vector *l) { - m_transient.resolveMultiMatches(var, l); + m_transient->resolveMultiMatches(var, l); } @@ -209,7 +209,7 @@ void Collections::resolveMultiMatches(const std::string& var, void Collections::resolveRegularExpression(const std::string& var, std::vector *l) { - m_transient.resolveRegularExpression(var, l); + m_transient->resolveRegularExpression(var, l); } diff --git a/src/collection/global_collections.cc b/src/collection/global_collections.cc new file mode 100644 index 00000000..ddf20348 --- /dev/null +++ b/src/collection/global_collections.cc @@ -0,0 +1,128 @@ +/* + * 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 "modsecurity/collection/global_collection.h" + +#ifdef __cplusplus +#include +#include +#include +#include +#endif + +#include "src/utils.h" + +namespace modsecurity { +namespace collection { + + +GlobalCollection::GlobalCollection() { + this->reserve(1000); +} + +GlobalCollection::~GlobalCollection() { + this->clear(); +} + +void GlobalCollection::store(std::string key, std::string compartment, + std::string value) { + this->emplace(new CollectionKey(key, compartment), value); +} + + +bool GlobalCollection::storeOrUpdateFirst(const std::string &key, + std::string compartment, const std::string &value) { + if (updateFirst(key, compartment, value) == false) { + store(key, compartment, value); + } + return true; +} + + +bool GlobalCollection::updateFirst(const std::string &key, + std::string compartment, const std::string &value) { + auto range = this->equal_range(new CollectionKey(key, compartment)); + + for (auto it = range.first; it != range.second; ++it) { + it->second = value; + return true; + } + return false; +} + + +void GlobalCollection::del(const std::string& key, std::string compartment) { + this->erase(new CollectionKey(key, compartment)); +} + + + +void GlobalCollection::resolveSingleMatch(const std::string& var, + std::string compartment, std::vector *l) { + auto range = this->equal_range(new CollectionKey(var, compartment)); + + for (auto it = range.first; it != range.second; ++it) { + l->push_back(new Variable(var, it->second)); + } +} + +void GlobalCollection::resolveMultiMatches(const std::string& var, + std::string compartment, std::vector *l) { + size_t keySize = var.size(); + l->reserve(15); + + auto range = this->equal_range(new CollectionKey(var, compartment)); + + for (auto it = range.first; it != range.second; ++it) { + l->insert(l->begin(), new Variable(var, it->second)); + } + + for (const auto& x : *this) { + if (x.first->m_name.size() <= keySize + 1) { + continue; + } + if (x.first->m_name.at(keySize) != ':') { + continue; + } + if (x.first->m_name.compare(0, keySize, var) != 0) { + continue; + } + l->insert(l->begin(), + new Variable(x.first->m_name, x.second)); + } +} + + +void GlobalCollection::resolveRegularExpression(const std::string& var, + std::string compartment, std::vector *l) { + /* Not ready */ +} + + +std::string* GlobalCollection::resolveFirst(const std::string& var, + std::string compartment) { + auto range = equal_range(new CollectionKey(var, compartment)); + + for (auto it = range.first; it != range.second; ++it) { + return &it->second; + } + + return NULL; +} + + +} // namespace collection +} // namespace modsecurity diff --git a/src/collection/collection.cc b/src/collections/collection.cc similarity index 82% rename from src/collection/collection.cc rename to src/collections/collection.cc index bef9a05f..bcf77705 100644 --- a/src/collection/collection.cc +++ b/src/collections/collection.cc @@ -14,7 +14,7 @@ */ -#include "modsecurity/collection/collection.h" +#include "modsecurity/transaction/collections.h" #ifdef __cplusplus #include @@ -23,11 +23,11 @@ #include #endif -#include "modsecurity/collection/variable.h" +#include "modsecurity/transaction/variable.h" #include "src/utils.h" namespace modsecurity { -namespace collection { +namespace transaction { Collection::Collection() { @@ -69,24 +69,24 @@ void Collection::del(const std::string& key) { void Collection::resolveSingleMatch(const std::string& var, - std::vector *l) { + std::vector *l) { auto range = this->equal_range(var); for (auto it = range.first; it != range.second; ++it) { - l->push_back(new Variable(var, it->second)); + l->push_back(new transaction::Variable(var, it->second)); } } void Collection::resolveMultiMatches(const std::string& var, - std::vector *l) { + std::vector *l) { size_t keySize = var.size(); l->reserve(15); auto range = this->equal_range(var); for (auto it = range.first; it != range.second; ++it) { - l->insert(l->begin(), new Variable(var, it->second)); + l->insert(l->begin(), new transaction::Variable(var, it->second)); } for (const auto& x : *this) { @@ -99,13 +99,13 @@ void Collection::resolveMultiMatches(const std::string& var, if (x.first.compare(0, keySize, var) != 0) { continue; } - l->insert(l->begin(), new Variable(x.first, x.second)); + l->insert(l->begin(), new transaction::Variable(x.first, x.second)); } } void Collection::resolveRegularExpression(const std::string& var, - std::vector *l) { + std::vector *l) { /* Not ready */ } @@ -121,5 +121,5 @@ std::string* Collection::resolveFirst(const std::string& var) { } -} // namespace collection +} // namespace transaction } // namespace modsecurity diff --git a/src/collections/collections.cc b/src/collections/collections.cc new file mode 100644 index 00000000..04fa5cda --- /dev/null +++ b/src/collections/collections.cc @@ -0,0 +1,239 @@ +/* + * 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 "modsecurity/transaction/collections.h" + +#ifdef __cplusplus +#include +#include +#include +#include +#include +#endif + +#include "modsecurity/transaction/variable.h" +#include "modsecurity/transaction/collection.h" +#include "src/utils.h" + +namespace modsecurity { +namespace transaction { + + +Collections::Collections(GlobalCollection *global, + GlobalCollection *ip) + : m_global_collection_key(""), + m_ip_collection_key(""), + m_global_collection(global), + m_ip_collection(ip) { + /* Create collection TX */ + this->emplace("TX", new Collection()); +} + + +Collections::~Collections() { + for (const auto &thing : *this) { + delete thing.second; + } + this->clear(); +} + +void Collections::storeOrUpdateFirst(const std::string& collectionName, + const std::string& variableName, + const std::string& targetValue) { + if (tolower(collectionName) == "ip" + && !m_ip_collection_key.empty()) { + m_ip_collection->storeOrUpdateFirst(collectionName + ":" + + variableName, m_ip_collection_key, targetValue); + return; + } + + if (tolower(collectionName) == "global" + && !m_global_collection_key.empty()) { + m_global_collection->storeOrUpdateFirst(collectionName + ":" + + variableName, m_global_collection_key, targetValue); + return; + } + + try { + Collection *collection; + collection = this->at(collectionName); + collection->storeOrUpdateFirst(collectionName + ":" + + variableName, targetValue); + } catch (...) { +#if 0 + debug(9, "don't know any collection named: " + + collectionName + ". it was created?"); +#endif + } +} + + +void Collections::store(std::string key, std::string value) { + m_transient.store(key, value); +} + + +bool Collections::storeOrUpdateFirst(const std::string &key, + const std::string &value) { + return m_transient.storeOrUpdateFirst(key, value); +} + + +bool Collections::updateFirst(const std::string &key, + const std::string &value) { + return m_transient.updateFirst(key, value); +} + + +void Collections::del(const std::string& key) { + return m_transient.del(key); +} + + +std::string* Collections::resolveFirst(const std::string& var) { + std::string *transientVar = m_transient.resolveFirst(var); + + if (transientVar != NULL) { + return transientVar; + } + + for (auto &a : *this) { + auto range = a.second->equal_range(var); + for (auto it = range.first; it != range.second; ++it) { + return & it->second; + } + } + + return NULL; +} + + +std::string* Collections::resolveFirst(const std::string& collectionName, + const std::string& var) { + if (tolower(collectionName) == "ip" + && !m_ip_collection_key.empty()) { + return m_ip_collection->resolveFirst(toupper(collectionName) + + ":" + var, m_ip_collection_key); + } + + if (tolower(collectionName) == "global" + && !m_global_collection_key.empty()) { + return m_global_collection->resolveFirst(toupper(collectionName) + + ":" + var, m_global_collection_key); + } + + for (auto &a : *this) { + if (tolower(a.first) == tolower(collectionName)) { + Collection *t = a.second; + auto range = t->equal_range(toupper(collectionName) + + ":" + var); + for (auto it = range.first; it != range.second; ++it) { + return &it->second; + } + } + } + + return NULL; +} + + +void Collections::resolveSingleMatch(const std::string& var, + std::vector *l) { + + m_transient.resolveSingleMatch(var, l); +} + + +void Collections::resolveSingleMatch(const std::string& var, + const std::string& collection, + std::vector *l) { + + if (tolower(collection) == "ip" + && !m_ip_collection_key.empty()) { + m_ip_collection->resolveSingleMatch(var, m_ip_collection_key, l); + return; + } + + if (tolower(collection) == "global" + && !m_global_collection_key.empty()) { + m_global_collection->resolveSingleMatch(var, + m_global_collection_key, l); + return; + } + + try { + this->at(collection)->resolveSingleMatch(var, l); + } catch (...) { } +} + +void Collections::resolveMultiMatches(const std::string& var, + std::vector *l) { + + m_transient.resolveMultiMatches(var, l); +} + + +void Collections::resolveMultiMatches(const std::string& var, + const std::string& collection, + std::vector *l) { + if (tolower(collection) == "ip" + && !m_ip_collection_key.empty()) { + m_ip_collection->resolveMultiMatches(var, m_ip_collection_key, l); + return; + } + + if (tolower(collection) == "global" + && !m_global_collection_key.empty()) { + m_global_collection->resolveMultiMatches(var, + m_global_collection_key, l); + return; + } + + try { + this->at(collection)->resolveMultiMatches(var, l); + } catch (...) { } +} + +void Collections::resolveRegularExpression(const std::string& var, + std::vector *l) { + m_transient.resolveRegularExpression(var, l); +} + + +void Collections::resolveRegularExpression(const std::string& var, + const std::string& collection, + std::vector *l) { + if (tolower(collection) == "ip" + && !m_ip_collection_key.empty()) { + m_ip_collection->resolveRegularExpression(toupper(collection) + + ":" + var, m_ip_collection_key, l); + return; + } + + if (tolower(collection) == "global" + && !m_global_collection_key.empty()) { + m_global_collection->resolveRegularExpression(toupper(collection) + + ":" + var, m_global_collection_key, l); + return; + } + + try { + this->at(collection)->resolveRegularExpression(var, l); + } catch (...) { } +} + +} // namespace transaction +} // namespace modsecurity diff --git a/src/transaction.cc b/src/transaction.cc index e5201850..f5816e44 100644 --- a/src/transaction.cc +++ b/src/transaction.cc @@ -1327,21 +1327,15 @@ std::string Transaction::toOldAuditLogFormat(int parts, audit_log << std::endl; if (parts & audit_log::AuditLog::BAuditLogPart) { + std::vector l; audit_log << "--" << trailer << "-" << "B--" << std::endl; audit_log << this->m_method << " " << this->m_uri << " " << "HTTP/"; audit_log << this->m_httpVersion << std::endl; - for (auto h : m_collections.m_transient) { - std::string filter = "REQUEST_HEADERS:"; - std::string a = h.first; - std::string b = h.second; - - if (a.compare(0, filter.length(), filter) == 0) { - if (a.length() > filter.length()) { - audit_log << a.c_str() + filter.length() << ": "; - audit_log << b.c_str() << std::endl; - } - } + m_collections.m_transient->resolveMultiMatches("REQUEST_HEADERS", &l); + for (auto h : l) { + audit_log << h->m_key.c_str() << ": "; + audit_log << h->m_value.c_str() << std::endl; } } if (parts & audit_log::AuditLog::CAuditLogPart) { @@ -1357,18 +1351,13 @@ std::string Transaction::toOldAuditLogFormat(int parts, /** TODO: write audit_log E part. */ } if (parts & audit_log::AuditLog::FAuditLogPart) { - audit_log << "--" << trailer << "-" << "F--" << std::endl; - for (auto h : m_collections.m_transient) { - std::string filter = "RESPONSE_HEADERS:"; - std::string a = h.first; - std::string b = h.second; + std::vector l; - if (a.compare(0, filter.length(), filter) == 0) { - if (a.length() > filter.length()) { - audit_log << a.c_str() + filter.length() << ": "; - audit_log << b.c_str() << std::endl; - } - } + audit_log << "--" << trailer << "-" << "F--" << std::endl; + m_collections.m_transient->resolveMultiMatches("RESPONSE_HEADERS", &l); + for (auto h : l) { + audit_log << h->m_key.c_str() << ": "; + audit_log << h->m_value.c_str() << std::endl; } } if (parts & audit_log::AuditLog::GAuditLogPart) { @@ -1443,20 +1432,15 @@ std::string Transaction::toJSON(int parts) { /* request headers */ if (parts & audit_log::AuditLog::BAuditLogPart) { + std::vector l; yajl_gen_string(g, reinterpret_cast("headers"), strlen("headers")); yajl_gen_map_open(g); - for (auto h : m_collections.m_transient) { - std::string filter = "REQUEST_HEADERS:"; - std::string a = h.first; - std::string b = h.second; - if (a.compare(0, filter.length(), filter) == 0) { - if (a.length() > filter.length()) { - LOGFY_ADD(a.c_str() + filter.length(), b.c_str()); - } - } + m_collections.m_transient->resolveMultiMatches("REQUEST_HEADERS", &l); + for (auto h : l) { + LOGFY_ADD(h->m_key.c_str(), h->m_value.c_str()); } /* end: request headers */ @@ -1478,21 +1462,16 @@ std::string Transaction::toJSON(int parts) { /* response headers */ if (parts & audit_log::AuditLog::FAuditLogPart) { + std::vector l; yajl_gen_string(g, reinterpret_cast("headers"), strlen("headers")); yajl_gen_map_open(g); - for (auto h : m_collections.m_transient) { - std::string filter = "RESPONSE_HEADERS:"; - std::string a = h.first; - std::string b = h.second; - - if (a.compare(0, filter.length(), filter) == 0) { - if (a.length() > filter.length()) { - LOGFY_ADD(a.c_str() + filter.length(), b.c_str()); - } - } + m_collections.m_transient->resolveMultiMatches("RESPONSE_HEADERS", &l); + for (auto h : l) { + LOGFY_ADD(h->m_key.c_str(), h->m_value.c_str()); } + /* end: response headers */ yajl_gen_map_close(g); }