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/pm.h"
17
18 #include <string.h>
19
20 #include <string>
21 #include <algorithm>
22 #include <iterator>
23 #include <sstream>
24 #include <vector>
25 #include <list>
26 #include <memory>
27
28 #include "src/operators/operator.h"
29 #include "src/utils/acmp.h"
30 #include "src/utils/string.h"
31
32 namespace modsecurity {
33 namespace operators {
34
~Pm()35 Pm::~Pm() {
36 acmp_node_t *root = m_p->root_node;
37
38 cleanup(root);
39
40 free(m_p);
41 m_p = NULL;
42 #ifdef MODSEC_MUTEX_ON_PM
43 pthread_mutex_destroy(&m_lock);
44 #endif
45 }
46
47
cleanup(acmp_node_t * n)48 void Pm::cleanup(acmp_node_t *n) {
49 if (n == NULL) {
50 return;
51 }
52
53 cleanup(n->sibling);
54 cleanup(n->child);
55
56 postOrderTraversal(n->btree);
57
58 if (n->text && strlen(n->text) > 0) {
59 free(n->text);
60 n->text = NULL;
61 }
62
63 if (n->pattern && strlen(n->pattern) > 0) {
64 free(n->pattern);
65 n->pattern = NULL;
66 }
67
68 free(n);
69 }
70
71
postOrderTraversal(acmp_btree_node_t * node)72 void Pm::postOrderTraversal(acmp_btree_node_t *node) {
73 if (node == NULL) {
74 return;
75 }
76
77 postOrderTraversal(node->right);
78 postOrderTraversal(node->left);
79
80 free(node);
81 }
82
83
evaluate(Transaction * transaction,RuleWithActions * rule,const std::string & input,std::shared_ptr<RuleMessage> ruleMessage)84 bool Pm::evaluate(Transaction *transaction, RuleWithActions *rule,
85 const std::string &input, std::shared_ptr<RuleMessage> ruleMessage) {
86 int rc;
87 ACMPT pt;
88 pt.parser = m_p;
89 pt.ptr = NULL;
90 const char *match = NULL;
91 #ifdef MODSEC_MUTEX_ON_PM
92 pthread_mutex_lock(&m_lock);
93 #endif
94 rc = acmp_process_quick(&pt, &match, input.c_str(), input.length());
95 #ifdef MODSEC_MUTEX_ON_PM
96 pthread_mutex_unlock(&m_lock);
97 #endif
98
99 if (rc >= 0 && transaction) {
100 std::string match_(match?match:"");
101 logOffset(ruleMessage, rc - match_.size() + 1, match_.size());
102 transaction->m_matched.push_back(match_);
103
104 if (rule && rule->hasCaptureAction()) {
105 transaction->m_collections.m_tx_collection->storeOrUpdateFirst("0",
106 match_);
107 ms_dbg_a(transaction, 7, "Added pm match TX.0: " + \
108 match_);
109 }
110 }
111
112 return rc >= 0;
113 }
114
115
init(const std::string & file,std::string * error)116 bool Pm::init(const std::string &file, std::string *error) {
117 std::vector<std::string> vec;
118 std::istringstream *iss;
119 const char *err = NULL;
120
121 #ifdef MODSEC_MUTEX_ON_PM
122 pthread_mutex_init(&m_lock, NULL);
123 #endif
124 char *content = parse_pm_content(m_param.c_str(), m_param.length(), &err);
125 if (content == NULL) {
126 iss = new std::istringstream(m_param);
127 } else {
128 iss = new std::istringstream(content);
129 }
130
131 std::copy(std::istream_iterator<std::string>(*iss),
132 std::istream_iterator<std::string>(),
133 back_inserter(vec));
134
135 for (auto &a : vec) {
136 acmp_add_pattern(m_p, a.c_str(), NULL, NULL, a.length());
137 }
138
139 while (m_p->is_failtree_done == 0) {
140 acmp_prepare(m_p);
141 }
142
143 if (content) {
144 free(content);
145 content = NULL;
146 }
147
148 delete iss;
149
150 return true;
151 }
152
153
154 } // namespace operators
155 } // namespace modsecurity
156