Skip to content

Commit eaba30f

Browse files
committed
fix: add PCRE2 capability to standalone module
1 parent 1a2de10 commit eaba30f

File tree

1 file changed

+237
-162
lines changed

1 file changed

+237
-162
lines changed

standalone/regex.c

Lines changed: 237 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,237 @@
1-
/*
2-
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
3-
* Copyright (c) 2004-2013 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 [email protected].
13-
*/
14-
15-
#include <limits.h>
16-
17-
#include "http_core.h"
18-
#include "http_request.h"
19-
20-
#include "modsecurity.h"
21-
#include "apache2.h"
22-
#include "http_main.h"
23-
#include "http_connection.h"
24-
25-
#include "apr_optional.h"
26-
#include "mod_log_config.h"
27-
28-
#include "msc_logging.h"
29-
#include "msc_util.h"
30-
31-
#include "ap_mpm.h"
32-
#include "scoreboard.h"
33-
34-
#include "apr_version.h"
35-
36-
#include "apr_lib.h"
37-
#include "ap_config.h"
38-
#include "http_config.h"
39-
40-
41-
static apr_status_t regex_cleanup(void *preg)
42-
{
43-
ap_regfree((ap_regex_t *) preg);
44-
return APR_SUCCESS;
45-
}
46-
47-
AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
48-
int cflags)
49-
{
50-
ap_regex_t *preg = apr_palloc(p, sizeof *preg);
51-
52-
if (ap_regcomp(preg, pattern, cflags)) {
53-
return NULL;
54-
}
55-
56-
apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
57-
apr_pool_cleanup_null);
58-
59-
return preg;
60-
}
61-
62-
AP_DECLARE(void) ap_regfree(ap_regex_t *preg)
63-
{
64-
(pcre_free)(preg->re_pcre);
65-
}
66-
67-
AP_DECLARE(int) ap_regcomp(ap_regex_t *preg, const char *pattern, int cflags)
68-
{
69-
const char *errorptr;
70-
int erroffset;
71-
int options = 0;
72-
int nsub = 0;
73-
74-
if ((cflags & AP_REG_ICASE) != 0) options |= PCRE_CASELESS;
75-
if ((cflags & AP_REG_NEWLINE) != 0) options |= PCRE_MULTILINE;
76-
77-
preg->re_pcre = pcre_compile(pattern, options, &errorptr, &erroffset, NULL);
78-
preg->re_erroffset = erroffset;
79-
80-
if (preg->re_pcre == NULL) return AP_REG_INVARG;
81-
82-
pcre_fullinfo((const pcre *)preg->re_pcre, NULL, PCRE_INFO_CAPTURECOUNT, &nsub);
83-
preg->re_nsub = nsub;
84-
return 0;
85-
}
86-
87-
#ifndef POSIX_MALLOC_THRESHOLD
88-
#define POSIX_MALLOC_THRESHOLD (10)
89-
#endif
90-
91-
AP_DECLARE(int) ap_regexec(const ap_regex_t *preg, const char *string,
92-
apr_size_t nmatch, ap_regmatch_t pmatch[],
93-
int eflags)
94-
{
95-
int rc;
96-
int options = 0;
97-
int *ovector = NULL;
98-
int small_ovector[POSIX_MALLOC_THRESHOLD * 3];
99-
int allocated_ovector = 0;
100-
101-
if ((eflags & AP_REG_NOTBOL) != 0) options |= PCRE_NOTBOL;
102-
if ((eflags & AP_REG_NOTEOL) != 0) options |= PCRE_NOTEOL;
103-
104-
((ap_regex_t *)preg)->re_erroffset = (apr_size_t)(-1); /* Only has meaning after compile */
105-
106-
if (nmatch > 0)
107-
{
108-
if (nmatch <= POSIX_MALLOC_THRESHOLD)
109-
{
110-
ovector = &(small_ovector[0]);
111-
}
112-
else
113-
{
114-
ovector = (int *)malloc(sizeof(int) * nmatch * 3);
115-
if (ovector == NULL) return AP_REG_ESPACE;
116-
allocated_ovector = 1;
117-
}
118-
}
119-
120-
rc = pcre_exec((const pcre *)preg->re_pcre, NULL, string, (int)strlen(string),
121-
0, options, ovector, nmatch * 3);
122-
123-
if (rc == 0) rc = nmatch; /* All captured slots were filled in */
124-
125-
if (rc >= 0)
126-
{
127-
apr_size_t i;
128-
for (i = 0; i < (apr_size_t)rc; i++)
129-
{
130-
pmatch[i].rm_so = ovector[i*2];
131-
pmatch[i].rm_eo = ovector[i*2+1];
132-
}
133-
if (allocated_ovector) free(ovector);
134-
for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1;
135-
return 0;
136-
}
137-
138-
else
139-
{
140-
if (allocated_ovector) free(ovector);
141-
switch(rc)
142-
{
143-
case PCRE_ERROR_NOMATCH: return AP_REG_NOMATCH;
144-
case PCRE_ERROR_NULL: return AP_REG_INVARG;
145-
case PCRE_ERROR_BADOPTION: return AP_REG_INVARG;
146-
case PCRE_ERROR_BADMAGIC: return AP_REG_INVARG;
147-
case PCRE_ERROR_UNKNOWN_NODE: return AP_REG_ASSERT;
148-
case PCRE_ERROR_NOMEMORY: return AP_REG_ESPACE;
149-
#ifdef PCRE_ERROR_MATCHLIMIT
150-
case PCRE_ERROR_MATCHLIMIT: return AP_REG_ESPACE;
151-
#endif
152-
#ifdef PCRE_ERROR_BADUTF8
153-
case PCRE_ERROR_BADUTF8: return AP_REG_INVARG;
154-
#endif
155-
#ifdef PCRE_ERROR_BADUTF8_OFFSET
156-
case PCRE_ERROR_BADUTF8_OFFSET: return AP_REG_INVARG;
157-
#endif
158-
default: return AP_REG_ASSERT;
159-
}
160-
}
161-
}
162-
1+
/*
2+
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
3+
* Copyright (c) 2004-2013 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 [email protected].
13+
*/
14+
15+
#include <limits.h>
16+
17+
#include "http_core.h"
18+
#include "http_request.h"
19+
20+
#include "modsecurity.h"
21+
#include "apache2.h"
22+
#include "http_main.h"
23+
#include "http_connection.h"
24+
25+
#include "apr_optional.h"
26+
#include "mod_log_config.h"
27+
28+
#include "msc_logging.h"
29+
#include "msc_util.h"
30+
31+
#include "ap_mpm.h"
32+
#include "scoreboard.h"
33+
34+
#include "apr_version.h"
35+
36+
#include "apr_lib.h"
37+
#include "ap_config.h"
38+
#include "http_config.h"
39+
40+
41+
static apr_status_t regex_cleanup(void *preg)
42+
{
43+
ap_regfree((ap_regex_t *) preg);
44+
return APR_SUCCESS;
45+
}
46+
47+
AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
48+
int cflags)
49+
{
50+
ap_regex_t *preg = apr_palloc(p, sizeof *preg);
51+
52+
if (ap_regcomp(preg, pattern, cflags)) {
53+
return NULL;
54+
}
55+
56+
apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
57+
apr_pool_cleanup_null);
58+
59+
return preg;
60+
}
61+
62+
AP_DECLARE(void) ap_regfree(ap_regex_t *preg)
63+
{
64+
#ifdef WITH_PCRE2
65+
(pcre2_code_free)(preg->re_pcre);
66+
#else
67+
(pcre_free)(preg->re_pcre);
68+
#endif
69+
}
70+
71+
AP_DECLARE(int) ap_regcomp(ap_regex_t *preg, const char *pattern, int cflags)
72+
{
73+
const char *errorptr;
74+
int erroffset;
75+
int options = 0;
76+
int nsub = 0;
77+
78+
#ifdef WITH_PCRE2
79+
if ((cflags & AP_REG_ICASE) != 0) options |= PCRE2_CASELESS;
80+
if ((cflags & AP_REG_NEWLINE) != 0) options |= PCRE2_MULTILINE;
81+
int error_number = 0;
82+
PCRE2_SIZE error_offset = 0;
83+
PCRE2_SPTR pcre2_pattern = (PCRE2_SPTR)pattern;
84+
85+
preg->re_pcre = pcre2_compile(pcre2_pattern, PCRE2_ZERO_TERMINATED,
86+
options, &error_number, &error_offset, NULL);
87+
preg->re_erroffset = error_offset;
88+
89+
if (preg->re_pcre == NULL) return AP_REG_INVARG;
90+
91+
pcre2_pattern_info((const pcre2_code *)preg->re_pcre, PCRE2_INFO_CAPTURECOUNT, &nsub);
92+
preg->re_nsub = nsub;
93+
94+
#else
95+
if ((cflags & AP_REG_ICASE) != 0) options |= PCRE_CASELESS;
96+
if ((cflags & AP_REG_NEWLINE) != 0) options |= PCRE_MULTILINE;
97+
98+
preg->re_pcre = pcre_compile(pattern, options, &errorptr, &erroffset, NULL);
99+
preg->re_erroffset = erroffset;
100+
101+
if (preg->re_pcre == NULL) return AP_REG_INVARG;
102+
103+
pcre_fullinfo((const pcre *)preg->re_pcre, NULL, PCRE_INFO_CAPTURECOUNT, &nsub);
104+
preg->re_nsub = nsub;
105+
#endif // end of WITH_PCRE
106+
return 0;
107+
}
108+
109+
#ifndef POSIX_MALLOC_THRESHOLD
110+
#define POSIX_MALLOC_THRESHOLD (10)
111+
#endif
112+
113+
AP_DECLARE(int) ap_regexec(const ap_regex_t *preg, const char *string,
114+
apr_size_t nmatch, ap_regmatch_t pmatch[],
115+
int eflags)
116+
{
117+
int rc;
118+
int options = 0;
119+
int *ovector = NULL;
120+
int small_ovector[POSIX_MALLOC_THRESHOLD * 3];
121+
int allocated_ovector = 0;
122+
123+
#ifdef WITH_PCRE2
124+
if ((eflags & AP_REG_NOTBOL) != 0) options |= PCRE2_NOTBOL;
125+
if ((eflags & AP_REG_NOTEOL) != 0) options |= PCRE2_NOTEOL;
126+
#else
127+
if ((eflags & AP_REG_NOTBOL) != 0) options |= PCRE_NOTBOL;
128+
if ((eflags & AP_REG_NOTEOL) != 0) options |= PCRE_NOTEOL;
129+
#endif
130+
131+
((ap_regex_t *)preg)->re_erroffset = (apr_size_t)(-1); /* Only has meaning after compile */
132+
133+
if (nmatch > 0)
134+
{
135+
if (nmatch <= POSIX_MALLOC_THRESHOLD)
136+
{
137+
ovector = &(small_ovector[0]);
138+
}
139+
else
140+
{
141+
ovector = (int *)malloc(sizeof(int) * nmatch * 3);
142+
if (ovector == NULL) return AP_REG_ESPACE;
143+
allocated_ovector = 1;
144+
}
145+
}
146+
147+
#ifdef WITH_PCRE2
148+
{
149+
PCRE2_SPTR pcre2_s;
150+
int pcre2_ret;
151+
pcre2_match_data *match_data;
152+
PCRE2_SIZE *pcre2_ovector = NULL;
153+
154+
pcre2_s = (PCRE2_SPTR)string;
155+
match_data = pcre2_match_data_create_from_pattern(preg->re_pcre, NULL);
156+
pcre2_match_context *match_context = pcre2_match_context_create(NULL);
157+
158+
pcre2_ret = pcre2_match((const pcre2_code *)preg->re_pcre, pcre2_s, (int)strlen(string),
159+
0, (uint32_t)options, match_data, match_context);
160+
161+
if (match_data != NULL) {
162+
pcre2_ovector = pcre2_get_ovector_pointer(match_data);
163+
if (pcre2_ovector != NULL) {
164+
for (int i = 0; ((i < pcre2_ret) && ((i*2) <= nmatch * 3)); i++) {
165+
if ((i*2) < nmatch * 3) {
166+
ovector[2*i] = pcre2_ovector[2*i];
167+
ovector[2*i+1] = pcre2_ovector[2*i+1];
168+
}
169+
}
170+
}
171+
pcre2_match_data_free(match_data);
172+
pcre2_match_context_free(match_context);
173+
}
174+
}
175+
#else
176+
rc = pcre_exec((const pcre *)preg->re_pcre, NULL, string, (int)strlen(string),
177+
0, options, ovector, nmatch * 3);
178+
#endif
179+
180+
if (rc == 0) rc = nmatch; /* All captured slots were filled in */
181+
182+
if (rc >= 0)
183+
{
184+
apr_size_t i;
185+
for (i = 0; i < (apr_size_t)rc; i++)
186+
{
187+
pmatch[i].rm_so = ovector[i*2];
188+
pmatch[i].rm_eo = ovector[i*2+1];
189+
}
190+
if (allocated_ovector) free(ovector);
191+
for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1;
192+
return 0;
193+
}
194+
195+
else
196+
{
197+
if (allocated_ovector) free(ovector);
198+
switch(rc)
199+
{
200+
#ifdef WITH_PCRE2
201+
case PCRE2_ERROR_NOMATCH: return AP_REG_NOMATCH;
202+
case PCRE2_ERROR_NULL: return AP_REG_INVARG;
203+
case PCRE2_ERROR_BADOPTION: return AP_REG_INVARG;
204+
case PCRE2_ERROR_BADMAGIC: return AP_REG_INVARG;
205+
// case PCRE2_ERROR_UNKNOWN_NODE: return AP_REG_ASSERT; not defined in PCRE2
206+
case PCRE2_ERROR_NOMEMORY: return AP_REG_ESPACE;
207+
#ifdef PCRE2_ERROR_MATCHLIMIT
208+
case PCRE2_ERROR_MATCHLIMIT: return AP_REG_ESPACE;
209+
#endif
210+
#ifdef PCRE2_ERROR_BADUTF8
211+
case PCRE2_ERROR_BADUTF8: return AP_REG_INVARG;
212+
#endif
213+
#ifdef PCRE2_ERROR_BADUTF8_OFFSET
214+
case PCRE2_ERROR_BADUTF8_OFFSET: return AP_REG_INVARG;
215+
#endif
216+
#else // with old PCRE
217+
case PCRE_ERROR_NOMATCH: return AP_REG_NOMATCH;
218+
case PCRE_ERROR_NULL: return AP_REG_INVARG;
219+
case PCRE_ERROR_BADOPTION: return AP_REG_INVARG;
220+
case PCRE_ERROR_BADMAGIC: return AP_REG_INVARG;
221+
case PCRE_ERROR_UNKNOWN_NODE: return AP_REG_ASSERT;
222+
case PCRE_ERROR_NOMEMORY: return AP_REG_ESPACE;
223+
#ifdef PCRE_ERROR_MATCHLIMIT
224+
case PCRE_ERROR_MATCHLIMIT: return AP_REG_ESPACE;
225+
#endif
226+
#ifdef PCRE_ERROR_BADUTF8
227+
case PCRE_ERROR_BADUTF8: return AP_REG_INVARG;
228+
#endif
229+
#ifdef PCRE_ERROR_BADUTF8_OFFSET
230+
case PCRE_ERROR_BADUTF8_OFFSET: return AP_REG_INVARG;
231+
#endif
232+
#endif // end of WITH_PCRE
233+
default: return AP_REG_ASSERT;
234+
}
235+
}
236+
}
237+

0 commit comments

Comments
 (0)