d961b2abb343f8b50dcf91bfc008f66673dc9e7a
[ossec-hids.git] / src / os_regex / os_regex_compile.c
1 /*   $OSSEC, os_regex_compile.c, v0.1, 2006/01/02, Daniel B. Cid$   */
2
3 /* Copyright (C) 2009 Trend Micro Inc.
4  * All right reserved.
5  *
6  * This program is a free software; you can redistribute it
7  * and/or modify it under the terms of the GNU General Public
8  * License (version 2) as published by the FSF - Free Software
9  * Foundation
10  */
11
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <ctype.h>
17
18 #include "os_regex.h"
19 #include "os_regex_internal.h"
20
21
22 /** int OSRegex_Compile(char *pattern, OSRegex *reg, int flags) v0.1
23  * Compile a regular expression to be used later.
24  * Allowed flags are:
25  *      - OS_CASE_SENSITIVE
26  *      - OS_RETURN_SUBSTRING
27  * Returns 1 on success or 0 on error.
28  * The error code is set on reg->error.
29  */
30 int OSRegex_Compile(const char *pattern, OSRegex *reg, int flags)
31 {
32     size_t i = 0;
33     size_t count = 0;
34     int end_of_string = 0;
35     int parenthesis = 0;
36     unsigned prts_size = 0;
37     unsigned max_prts_size = 0;
38
39     char *pt;
40     char *new_str;
41     char *new_str_free = NULL;
42
43
44     /* Checking for references not initialized */
45     if(reg == NULL)
46     {
47         return(0);
48     }
49
50
51     /* Initializing OSRegex structure */
52     reg->error = 0;
53     reg->patterns = NULL;
54     reg->flags = NULL;
55     reg->prts_closure = NULL;
56     reg->prts_str = NULL;
57     reg->sub_strings = NULL;
58
59
60
61     /* The pattern can't be null */
62     if(pattern == NULL)
63     {
64         reg->error = OS_REGEX_PATTERN_NULL;
65         goto compile_error;
66     }
67
68     /* Maximum size of the pattern */
69     if(strlen(pattern) > OS_PATTERN_MAXSIZE)
70     {
71         reg->error = OS_REGEX_MAXSIZE;
72         goto compile_error;
73     }
74
75
76     /* Duping the pattern for our internal work */
77     new_str = strdup(pattern);
78     if(!new_str)
79     {
80         reg->error = OS_REGEX_OUTOFMEMORY;
81         goto compile_error;
82     }
83     new_str_free = new_str;
84     pt = new_str;
85
86
87     /* Getting the number of sub patterns */
88     do
89     {
90         if(*pt == BACKSLASH)
91         {
92             pt++;
93             /* Giving the new values for each regex */
94             switch(*pt)
95             {
96                 case 'd': *pt = 1;break;
97                 case 'w': *pt = 2;break;
98                 case 's': *pt = 3;break;
99                 case 'p': *pt = 4;break;
100                 case '(': *pt = 5;break;
101                 case ')': *pt = 6;break;
102                 case '\\':*pt = 7;break;
103                 case 'D': *pt = 8;break;
104                 case 'W': *pt = 9;break;
105                 case 'S': *pt = 10;break;
106                 case '.': *pt = 11;break;
107                 case 't': *pt = 12;break;
108                 case '$': *pt = 13;break;
109                 case '|': *pt = 14;break;
110                 case '<': *pt = 15;break;
111                 default:
112                     reg->error = OS_REGEX_BADREGEX;
113                     goto compile_error;
114             }
115             pt++;
116
117             continue;
118         }
119         else if(*pt == '(')
120         {
121             parenthesis++;
122         }
123         else if(*pt == ')')
124         {
125             /* Internally, open and closed are the same */
126             *pt = '(';
127             parenthesis--;
128             prts_size++;
129         }
130
131         /* We only allow one level of parenthesis */
132         if(parenthesis != 0 && parenthesis != 1)
133         {
134             reg->error = OS_REGEX_BADPARENTHESIS;
135             goto compile_error;
136         }
137
138         /* The pattern must be always lower case if
139          * case sensitive is set
140          */
141         if(!(flags & OS_CASE_SENSITIVE))
142         {
143             *pt = (char) charmap[(uchar)*pt];
144         }
145
146         if(*pt == OR)
147         {
148             /* Each sub pattern must be closed on parenthesis */
149             if(parenthesis != 0)
150             {
151                 reg->error = OS_REGEX_BADPARENTHESIS;
152                 goto compile_error;
153             }
154             count++;
155         }
156         pt++;
157     }while(*pt != '\0');
158
159
160     /* After the whole pattern is read, the parenthesis must all be closed */
161     if(parenthesis != 0)
162     {
163         reg->error = OS_REGEX_BADPARENTHESIS;
164         goto compile_error;
165     }
166
167
168     /* Allocating the memory for the sub patterns */
169     count++;
170     reg->patterns = (char **) calloc(count +1, sizeof(char *));
171     reg->flags = (int *) calloc(count +1, sizeof(int));
172
173     /* Memory allocation error check */
174     if(!reg->patterns || !reg->flags)
175     {
176         reg->error = OS_REGEX_OUTOFMEMORY;
177         goto compile_error;
178     }
179
180
181     /* For the substrings */
182     if((prts_size > 0) && (flags & OS_RETURN_SUBSTRING))
183     {
184         reg->prts_closure = (const char ***) calloc(count +1, sizeof(const char **));
185         reg->prts_str = (const char ***) calloc(count +1, sizeof(const char **));
186         if(!reg->prts_closure || !reg->prts_str)
187         {
188             reg->error = OS_REGEX_OUTOFMEMORY;
189             goto compile_error;
190         }
191     }
192
193
194     /* Initializing each sub pattern */
195     for(i = 0; i<=count; i++)
196     {
197         reg->patterns[i] = NULL;
198         reg->flags[i] = 0;
199
200         /* The parenthesis closure if set */
201         if(reg->prts_closure)
202         {
203             reg->prts_closure[i] = NULL;
204             reg->prts_str[i] = NULL;
205         }
206     }
207     i = 0;
208
209
210     /* Reassigning pt to the beginning of the string */
211     pt = new_str;
212
213
214     /* Getting the sub patterns */
215     do
216     {
217         if((*pt == OR) || (*pt == '\0'))
218         {
219             if(*pt == '\0')
220             {
221                 end_of_string = 1;
222             }
223
224             *pt = '\0';
225
226             /* If string starts with ^, set the BEGIN SET flag */
227             if(*new_str == BEGINREGEX)
228             {
229                 new_str++;
230                 reg->flags[i]|=BEGIN_SET;
231             }
232
233             /* If string ends with $, set the END_SET flag */
234             if(*(pt-1) == ENDREGEX)
235             {
236                 *(pt-1) = '\0';
237                 reg->flags[i]|=END_SET;
238             }
239
240             reg->patterns[i] = strdup(new_str);
241
242             if(!reg->patterns[i])
243             {
244                 reg->error = OS_REGEX_OUTOFMEMORY;
245                 goto compile_error;
246
247             }
248
249
250             /* Setting the parenthesis closures */
251             /* The parenthesis closure if set */
252             if(reg->prts_closure)
253             {
254                 unsigned tmp_int = 0;
255                 char *tmp_str;
256
257
258                 /* search the whole pattern for parenthesis */
259                 prts_size = 0;
260
261                 /* First loop we get the number of parenthesis.
262                  * We allocate the memory and loop again setting
263                  * the parenthesis closures.
264                  */
265                 tmp_str = reg->patterns[i];
266                 while(*tmp_str != '\0')
267                 {
268                     if(prts(*tmp_str))
269                     {
270                         prts_size++;
271                     }
272                     tmp_str++;
273                 }
274
275                 /* Getting the maximum number of parenthesis for
276                  * all sub strings. We need that to set up the maximum
277                  * number of substrings to be returned.
278                  */
279                 if(max_prts_size < prts_size)
280                 {
281                     max_prts_size = prts_size;
282                 }
283
284                 /* Allocating the memory */
285                 reg->prts_closure[i] = (const char **) calloc(prts_size + 1, sizeof(const char *));
286                 reg->prts_str[i] = (const char **) calloc(prts_size + 1, sizeof(const char *));
287                 if((reg->prts_closure[i] == NULL)||(reg->prts_str[i] == NULL))
288                 {
289                     reg->error = OS_REGEX_OUTOFMEMORY;
290                     goto compile_error;
291                 }
292
293                 /* Next loop to set the closures */
294                 tmp_str = reg->patterns[i];
295                 while(*tmp_str != '\0')
296                 {
297                     if(prts(*tmp_str))
298                     {
299                         if(tmp_int >= prts_size)
300                         {
301                             reg->error = OS_REGEX_BADPARENTHESIS;
302                             goto compile_error;
303                         }
304
305                         /* Setting to the pointer to the string */
306                         reg->prts_closure[i][tmp_int] = tmp_str;
307                         reg->prts_str[i][tmp_int] = NULL;
308
309                         tmp_int++;
310                     }
311
312                     tmp_str++;
313                 }
314             }
315
316
317             if(end_of_string)
318             {
319                 break;
320             }
321
322             new_str = ++pt;
323             i++;
324             continue;
325         }
326         pt++;
327
328     }while(!end_of_string);
329
330     /* Allocating sub string for the maximum number of parenthesis */
331     reg->sub_strings = (char **) calloc(max_prts_size + 1, sizeof(char *));
332     if(reg->sub_strings == NULL)
333     {
334         reg->error = OS_REGEX_OUTOFMEMORY;
335         goto compile_error;
336     }
337
338     /* Success return */
339     free(new_str_free);
340     return(1);
341
342
343     /* Error handling */
344     compile_error:
345
346     if(new_str_free)
347     {
348         free(new_str_free);
349     }
350
351     OSRegex_FreePattern(reg);
352
353     return(0);
354 }
355
356
357 /* EOF */