new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / os_regex / os_match_compile.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All right reserved.
3  *
4  * This program is a free software; you can redistribute it
5  * and/or modify it under the terms of the GNU General Public
6  * License (version 2) as published by the FSF - Free Software
7  * Foundation
8  */
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13
14 #include "os_regex.h"
15
16 int OSMatch_Execute_pcre2_match(const char *subject, size_t len, OSMatch *match);
17 int OSMatch_Execute_true(const char *subject, size_t len, OSMatch *match);
18 int OSMatch_Execute_strncmp(const char *subject, size_t len, OSMatch *match);
19 int OSMatch_Execute_strrcmp(const char *subject, size_t len, OSMatch *match);
20 int OSMatch_Execute_strcmp(const char *subject, size_t len, OSMatch *match);
21 int OSMatch_Execute_strncasecmp(const char *subject, size_t len, OSMatch *match);
22 int OSMatch_Execute_strrcasecmp(const char *subject, size_t len, OSMatch *match);
23 int OSMatch_Execute_strcasecmp(const char *subject, size_t len, OSMatch *match);
24 int OSMatch_CouldBeOptimized(const char *pattern2check);
25
26 /* Compile a pattern to be used later
27  * Allowed flags are:
28  *      - OS_CASE_SENSITIVE
29  * Returns 1 on success or 0 on error
30  * The error code is set on reg->error
31  */
32 int OSMatch_Compile(const char *pattern, OSMatch *reg, int flags)
33 {
34     char *pattern_pcre2 = NULL;
35     int flags_compile = 0;
36     int error = 0;
37     PCRE2_SIZE erroroffset = 0;
38     size_t pattern_len = 0UL;
39     char first_char, last_char;
40
41     /* Check for references not initialized */
42     if (reg == NULL) {
43         return (0);
44     }
45
46     /* Initialize OSMatch structure */
47     reg->error = 0;
48     reg->regex = NULL;
49     reg->match_data = NULL;
50     reg->pattern_len = 0UL;
51     reg->pattern = NULL;
52     reg->exec_function = NULL;
53
54     /* The pattern can't be null */
55     if (pattern == NULL) {
56         reg->error = OS_REGEX_PATTERN_NULL;
57         goto compile_error;
58     }
59
60     /* Maximum size of the pattern */
61     pattern_len = strlen(pattern);
62     if (pattern_len > OS_PATTERN_MAXSIZE) {
63         reg->error = OS_REGEX_MAXSIZE;
64         goto compile_error;
65     }
66
67     if (pattern_len == 0) {
68         reg->exec_function = OSMatch_Execute_true;
69         return (1);
70     } else if (OSMatch_CouldBeOptimized(pattern)) {
71         first_char = pattern[0];
72         last_char = pattern[pattern_len - 1];
73
74         if (first_char == '^') {
75             if (last_char == '$') {
76                 reg->pattern = strdup(&pattern[1]);
77                 reg->pattern_len = pattern_len - 2;
78                 reg->pattern[reg->pattern_len] = '\0';
79                 if (flags & OS_CASE_SENSITIVE) {
80                     reg->exec_function = OSMatch_Execute_strcmp;
81                 } else {
82                     reg->exec_function = OSMatch_Execute_strcasecmp;
83                 }
84                 return (1);
85             } else {
86                 reg->pattern = strdup(&pattern[1]);
87                 reg->pattern_len = pattern_len - 1;
88                 if (flags & OS_CASE_SENSITIVE) {
89                     reg->exec_function = OSMatch_Execute_strncmp;
90                 } else {
91                     reg->exec_function = OSMatch_Execute_strncasecmp;
92                 }
93                 return (1);
94             }
95         } else {
96             if (last_char == '$') {
97                 reg->pattern = strdup(pattern);
98                 reg->pattern_len = pattern_len - 1;
99                 reg->pattern[reg->pattern_len] = '\0';
100                 if (flags & OS_CASE_SENSITIVE) {
101                     reg->exec_function = OSMatch_Execute_strrcmp;
102                 } else {
103                     reg->exec_function = OSMatch_Execute_strrcasecmp;
104                 }
105                 return (1);
106             }
107         }
108     }
109
110     reg->exec_function = OSMatch_Execute_pcre2_match;
111
112     /* Ossec pattern conversion */
113     if (OSRegex_Convert(pattern, &pattern_pcre2, OS_CONVERT_MATCH) == 0) {
114         reg->error = OS_REGEX_BADREGEX;
115         goto compile_error;
116     }
117
118     flags_compile |= PCRE2_UTF;
119     flags_compile |= PCRE2_NO_UTF_CHECK;
120     flags_compile |= (flags & OS_CASE_SENSITIVE) ? 0 : PCRE2_CASELESS;
121     reg->regex = pcre2_compile((PCRE2_SPTR)pattern_pcre2, PCRE2_ZERO_TERMINATED, flags_compile,
122                                &error, &erroroffset, NULL);
123     if (reg->regex == NULL) {
124         reg->error = OS_REGEX_BADREGEX;
125         goto compile_error;
126     }
127
128     reg->match_data = pcre2_match_data_create_from_pattern(reg->regex, NULL);
129     if (reg->match_data == NULL) {
130         reg->error = OS_REGEX_OUTOFMEMORY;
131         goto compile_error;
132     }
133
134 #ifdef USE_PCRE2_JIT
135     /* Just In Time compilation for faster execution */
136     if (pcre2_jit_compile(reg->regex, PCRE2_JIT_COMPLETE) != 0) {
137         reg->error = OS_REGEX_NO_JIT;
138         goto compile_error;
139     }
140 #endif
141
142     free(pattern_pcre2);
143
144     return (1);
145
146 compile_error:
147     /* Error handling */
148
149     if (pattern_pcre2) {
150         free(pattern_pcre2);
151     }
152
153     OSMatch_FreePattern(reg);
154
155     return (0);
156 }
157
158 int OSMatch_CouldBeOptimized(const char *pattern2check)
159 {
160     return OS_Pcre2("^\\^?[^$|^]+\\$?$", pattern2check);
161 }
162