new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / config / rules-config.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 <string.h>
11
12 #include "config.h"
13 #include "shared.h"
14 #include "global-config.h"
15 #include "config.h"
16
17 /* Prototypes */
18 static int cmpr(const void *a, const void *b) __attribute__((nonnull));
19 static int file_in_list(unsigned int list_size, char *f_name, char *d_name, char **alist) __attribute__((nonnull));
20
21
22 static int cmpr(const void *a, const void *b)
23 {
24     return strcmp(*(const char *const *)a, *(const char *const *)b);
25 }
26
27 static int file_in_list(unsigned int list_size, char *f_name, char *d_name, char **alist)
28 {
29     unsigned int i = 0;
30     for (i = 0; (i + 1) < list_size; i++) {
31         if ((strcmp(alist[i], f_name) == 0 || strcmp(alist[i], d_name) == 0)) {
32             return (1);
33         }
34     }
35     return (0);
36 }
37
38 int Read_Rules(XML_NODE node, void *configp, __attribute__((unused)) void *mailp)
39 {
40     int i = 0;
41     unsigned int ii = 0;
42
43     unsigned int rules_size = 1;
44     unsigned int lists_size = 1;
45     unsigned int decoders_size = 1;
46
47     char path[PATH_MAX + 2];
48     char f_name[PATH_MAX + 2];
49     unsigned int start_point = 0;
50     int att_count = 0;
51     struct dirent *entry;
52     DIR *dfd;
53     OSRegex regex;
54
55     /* XML definitions */
56     const char *xml_rules_include = "include";
57     const char *xml_rules_rule = "rule";
58     const char *xml_rules_rules_dir = "rule_dir";
59     const char *xml_rules_lists = "list";
60     const char *xml_rules_decoders = "decoder";
61     const char *xml_rules_decoders_dir = "decoder_dir";
62
63     _Config *Config;
64
65     Config = (_Config *)configp;
66
67     /* Initialize OSRegex */
68     memset(&regex, 0, sizeof(regex));
69
70     while (node[i]) {
71         if (!node[i]->element) {
72             merror(XML_ELEMNULL, __local_name);
73             return (OS_INVALID);
74         } else if (!node[i]->content) {
75             merror(XML_VALUENULL, __local_name, node[i]->element);
76             return (OS_INVALID);
77         }
78         /* Mail notification */
79         else if ((strcmp(node[i]->element, xml_rules_include) == 0) ||
80                  (strcmp(node[i]->element, xml_rules_rule) == 0)) {
81             rules_size++;
82             Config->includes = (char **) realloc(Config->includes,
83                                                  sizeof(char *)*rules_size);
84             if (!Config->includes) {
85                 merror(MEM_ERROR, __local_name, errno, strerror(errno));
86                 return (OS_INVALID);
87             }
88
89             os_strdup(node[i]->content, Config->includes[rules_size - 2]);
90             Config->includes[rules_size - 1] = NULL;
91             debug1("adding rule: %s", node[i]->content);
92         } else if (strcmp(node[i]->element, xml_rules_decoders) == 0) {
93             decoders_size++;
94             Config->decoders = (char **) realloc(Config->decoders,
95                                                  sizeof(char *)*decoders_size);
96             if (!Config->decoders) {
97                 merror(MEM_ERROR, __local_name, errno, strerror(errno));
98                 return (OS_INVALID);
99             }
100
101             os_strdup(node[i]->content, Config->decoders[decoders_size - 2]);
102             Config->decoders[decoders_size - 1] = NULL;
103             debug1("adding decoder: %s", node[i]->content);
104         } else if (strcmp(node[i]->element, xml_rules_lists) == 0) {
105             lists_size++;
106             Config->lists = (char **) realloc(Config->lists,
107                                               sizeof(char *)*lists_size);
108             if (!Config->lists) {
109                 merror(MEM_ERROR, __local_name, errno, strerror(errno));
110                 return (OS_INVALID);
111             }
112             os_strdup(node[i]->content, Config->lists[lists_size - 2]);
113             Config->lists[lists_size - 1] = NULL;
114
115         } else if (strcmp(node[i]->element, xml_rules_decoders_dir) == 0) {
116
117             if (node[i]->attributes && node[i]->values) {
118                 while (node[i]->attributes[att_count]) {
119                     if ((strcasecmp(node[i]->attributes[att_count], "pattern") == 0)) {
120                         if (node[i]->values[att_count]) {
121                             if (!OSRegex_Compile(node[i]->values[att_count], &regex, 0)) {
122                                 merror(CONFIG_ERROR, __local_name, "pattern in decoders_dir does not compile");
123                                 merror("%s: ERROR: Regex would not compile", __local_name);
124                                 return (-1);
125                             }
126                         }
127                     }
128                     att_count++;
129                 }
130             } else {
131                 OSRegex_Compile(".xml$", &regex, 0);
132             }
133
134 #ifdef TESTRULE
135             snprintf(path, PATH_MAX + 1, "%s", node[i]->content);
136 #else
137             snprintf(path, PATH_MAX + 1, "%s/%s", DEFAULTDIR, node[i]->content);
138 #endif
139
140             f_name[PATH_MAX + 1] = '\0';
141             dfd = opendir(path);
142
143             att_count = 0; // Reset this variable after it was used in decoder 
144
145             if (dfd != NULL) {
146                 start_point = decoders_size - 1;
147                 while ((entry = readdir(dfd)) != NULL) {
148                     snprintf(f_name, PATH_MAX + 1, "%s/%s", node[i]->content, entry->d_name);
149
150                     /* Ignore . and ..  */
151                     if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) {
152                         continue;
153                     }
154
155                     /* No duplicates allowed */
156                     if (file_in_list(decoders_size, f_name, entry->d_name, Config->decoders)) {
157                         continue;
158                     }
159
160                     if (OSRegex_Execute(f_name, &regex)) {
161                         decoders_size++;
162                         Config->decoders = (char **) realloc(Config->decoders, sizeof(char *)*decoders_size);
163                         if (!Config->decoders) {
164                             merror(MEM_ERROR, __local_name, errno, strerror(errno));
165                             OSRegex_FreePattern(&regex);
166                             closedir(dfd);
167                             return (-1);
168                         }
169
170                         os_strdup(f_name, Config->decoders[decoders_size - 2]);
171                         Config->decoders[decoders_size - 1] = NULL;
172                         debug1("adding decoder: %s", f_name);
173                     } else {
174                         debug1("Regex does not match \"%s\"",  f_name);
175                     }
176                 }
177
178                 OSRegex_FreePattern(&regex);
179                 closedir(dfd);
180                 /* Sort just then newly added items */
181                 qsort(Config->decoders + start_point , decoders_size - start_point - 1, sizeof(char *), cmpr);
182             }
183             debug1("decoders_size %d", decoders_size);
184             for (ii = 0; ii < decoders_size - 1; ii++) {
185                 debug1("- %s", Config->decoders[ii]);
186             }
187         } else if (strcmp(node[i]->element, xml_rules_rules_dir) == 0) {
188             if (node[i]->attributes && node[i]->values) {
189                 while (node[i]->attributes[att_count]) {
190                     if ((strcasecmp(node[i]->attributes[att_count], "pattern") == 0)) {
191                         if (node[i]->values[att_count]) {
192                             if (!OSRegex_Compile(node[i]->values[att_count], &regex, 0)) {
193                                 merror(CONFIG_ERROR, __local_name, "pattern in rules_dir does not compile");
194                                 merror("%s: ERROR: Regex would not compile", __local_name);
195                                 return (-1);
196                             }
197                         }
198                     }
199                     att_count++;
200                 }
201             } else {
202                 OSRegex_Compile(".xml$", &regex, 0);
203             }
204
205 #ifdef TESTRULE
206             snprintf(path, PATH_MAX + 1, "%s", node[i]->content);
207 #else
208             snprintf(path, PATH_MAX + 1, "%s/%s", DEFAULTDIR, node[i]->content);
209 #endif
210
211             f_name[PATH_MAX + 1] = '\0';
212             dfd = opendir(path);
213
214             if (dfd != NULL) {
215                 start_point = rules_size - 1;
216                 while ((entry = readdir(dfd)) != NULL) {
217                     snprintf(f_name, PATH_MAX + 1, "%s/%s", node[i]->content, entry->d_name);
218
219                     /* Ignore . and ..  */
220                     if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) {
221                         continue;
222                     }
223
224                     /* No duplicates allowed */
225                     if (file_in_list(rules_size, f_name, entry->d_name, Config->includes)) {
226                         continue;
227                     }
228
229                     if (OSRegex_Execute(f_name, &regex)) {
230                         rules_size++;
231                         Config->includes = (char **) realloc(Config->includes, sizeof(char *)*rules_size);
232                         if (!Config->includes) {
233                             merror(MEM_ERROR, __local_name, errno, strerror(errno));
234                             OSRegex_FreePattern(&regex);
235                             closedir(dfd);
236                             return (-1);
237                         }
238
239                         os_strdup(f_name, Config->includes[rules_size - 2]);
240                         Config->includes[rules_size - 1] = NULL;
241                         debug1("adding rule: %s", f_name);
242                     } else {
243                         debug1("Regex does not match \"%s\"",  f_name);
244                     }
245                 }
246
247                 OSRegex_FreePattern(&regex);
248                 closedir(dfd);
249                 /* Sort just then newly added items */
250                 qsort(Config->includes + start_point , rules_size - start_point - 1, sizeof(char *), cmpr);
251             }
252         } else {
253             merror(XML_INVELEM, __local_name, node[i]->element);
254             OSRegex_FreePattern(&regex);
255             return (OS_INVALID);
256         }
257         i++;
258     }
259     return (0);
260 }