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