new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / config / localfile-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 "shared.h"
11 #include "localfile-config.h"
12 #include "config.h"
13
14
15 int Read_Localfile(XML_NODE node, void *d1, __attribute__((unused)) void *d2)
16 {
17     unsigned int pl = 0;
18     unsigned int i = 0;
19     unsigned int glob_set = 0;
20 #ifndef WIN32
21     int glob_offset = 0;
22 #endif
23
24     /* XML Definitions */
25     const char *xml_localfile_location = "location";
26     const char *xml_localfile_command = "command";
27     const char *xml_localfile_logformat = "log_format";
28     const char *xml_localfile_frequency = "frequency";
29     const char *xml_localfile_alias = "alias";
30     const char *xml_localfile_future = "only-future-events";
31     const char *xml_localfile_query = "query";
32
33     logreader *logf;
34     logreader_config *log_config;
35
36     log_config = (logreader_config *)d1;
37
38     /* If config is not set, create it */
39     if (!log_config->config) {
40         os_calloc(2, sizeof(logreader), log_config->config);
41         logf = log_config->config;
42         logf[0].file = NULL;
43         logf[0].command = NULL;
44         logf[0].alias = NULL;
45         logf[0].logformat = NULL;
46         logf[0].future = 0;
47         logf[0].query = NULL;
48         logf[1].file = NULL;
49         logf[1].command = NULL;
50         logf[1].alias = NULL;
51         logf[1].logformat = NULL;
52         logf[1].future = 0;
53         logf[1].query = NULL;
54     } else {
55         logf = log_config->config;
56         while (logf[pl].file != NULL) {
57             pl++;
58         }
59
60         /* Allocate more memory */
61         os_realloc(logf, (pl + 2)*sizeof(logreader), log_config->config);
62         logf = log_config->config;
63         logf[pl + 1].file = NULL;
64         logf[pl + 1].command = NULL;
65         logf[pl + 1].alias = NULL;
66         logf[pl + 1].logformat = NULL;
67         logf[pl + 1].future = 0;
68         logf[pl + 1].query = NULL;
69     }
70
71     logf[pl].file = NULL;
72     logf[pl].command = NULL;
73     logf[pl].alias = NULL;
74     logf[pl].logformat = NULL;
75     logf[pl].future = 0;
76     logf[pl].query = NULL;
77     logf[pl].fp = NULL;
78     logf[pl].ffile = NULL;
79     logf[pl].djb_program_name = NULL;
80     logf[pl].ign = 360;
81
82
83     /* Search for entries related to files */
84     i = 0;
85     while (node[i]) {
86         if (!node[i]->element) {
87             merror(XML_ELEMNULL, __local_name);
88             return (OS_INVALID);
89         } else if (!node[i]->content) {
90             merror(XML_VALUENULL, __local_name, node[i]->element);
91             return (OS_INVALID);
92         } else if (strcmp(node[i]->element, xml_localfile_future) == 0) {
93             if (strcmp(node[i]->content, "yes") == 0) {
94                 logf[pl].future = 1;
95             }
96         } else if (strcmp(node[i]->element, xml_localfile_query) == 0) {
97             os_strdup(node[i]->content, logf[pl].query);
98         } else if (strcmp(node[i]->element, xml_localfile_command) == 0) {
99             /* We don't accept remote commands from the manager - just in case */
100             if (log_config->agent_cfg == 1 && log_config->accept_remote == 0) {
101                 merror("%s: Remote commands are not accepted from the manager. "
102                        "Ignoring it on the agent.conf", __local_name);
103
104                 logf[pl].file = NULL;
105                 logf[pl].ffile = NULL;
106                 logf[pl].command = NULL;
107                 logf[pl].alias = NULL;
108                 logf[pl].logformat = NULL;
109                 logf[pl].fp = NULL;
110                 return (OS_INVALID);
111             }
112
113             os_strdup(node[i]->content, logf[pl].file);
114             logf[pl].command = logf[pl].file;
115         } else if (strcmp(node[i]->element, xml_localfile_frequency) == 0) {
116
117             if(strcmp(node[i]->content,  "hourly") == 0)
118             {
119                 logf[pl].ign = 3600;
120             }
121             else if(strcmp(node[i]->content,  "daily") == 0)
122             {
123                 logf[pl].ign = 86400;
124             }
125             else
126             {
127
128                 if (!OS_StrIsNum(node[i]->content)) {
129                     merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
130                     return (OS_INVALID);
131                 }
132
133                 logf[pl].ign = atoi(node[i]->content);
134             }
135         } else if (strcmp(node[i]->element, xml_localfile_location) == 0) {
136         #ifdef WIN32
137             /* Expand variables on Windows */
138             if (strchr(node[i]->content, '%')) {
139                 int expandreturn = 0;
140                 char newfile[OS_MAXSTR + 1];
141
142                 newfile[OS_MAXSTR] = '\0';
143                 expandreturn = ExpandEnvironmentStrings(node[i]->content,
144                                                         newfile, OS_MAXSTR);
145
146                 if ((expandreturn > 0) && (expandreturn < OS_MAXSTR)) {
147                     free(node[i]->content);
148
149                     os_strdup(newfile, node[i]->content);
150                 }
151             }
152         #endif
153
154             /* This is a glob*
155              * We will call this file multiple times until
156              * there is no one else available.
157              */
158 #ifndef WIN32 /* No windows support for glob */
159             if (strchr(node[i]->content, '*') ||
160                     strchr(node[i]->content, '?') ||
161                     strchr(node[i]->content, '[')) {
162                 glob_t g;
163
164                 /* Setting to the first entry of the glob */
165                 if (glob_set == 0) {
166                     glob_set = pl + 1;
167                 }
168
169                 if (glob(node[i]->content, 0, NULL, &g) != 0) {
170                     merror(GLOB_ERROR, __local_name, node[i]->content);
171                     os_strdup(node[i]->content, logf[pl].file);
172                     i++;
173                     continue;
174                 }
175
176                 /* Check for the last entry */
177                 if ((g.gl_pathv[glob_offset]) == NULL) {
178                     /* Check when nothing is found */
179                     if (glob_offset == 0) {
180                         merror(GLOB_NFOUND, __local_name, node[i]->content);
181                         return (OS_INVALID);
182                     }
183                     i++;
184                     continue;
185                 }
186
187
188                 while(g.gl_pathv[glob_offset] != NULL)
189                 {
190                     /* Check for strftime on globs too */
191                     if (strchr(g.gl_pathv[glob_offset], '%')) {
192                         struct tm *p;
193                         time_t l_time = time(0);
194                         char lfile[OS_FLSIZE + 1];
195                         size_t ret;
196
197                         p = localtime(&l_time);
198
199                         lfile[OS_FLSIZE] = '\0';
200                         ret = strftime(lfile, OS_FLSIZE, g.gl_pathv[glob_offset], p);
201                         if (ret == 0) {
202                             merror(PARSE_ERROR, __local_name, g.gl_pathv[glob_offset]);
203                             return (OS_INVALID);
204                         }
205
206                         os_strdup(g.gl_pathv[glob_offset], logf[pl].ffile);
207                         os_strdup(g.gl_pathv[glob_offset], logf[pl].file);
208                     } else {
209                         os_strdup(g.gl_pathv[glob_offset], logf[pl].file);
210                     }
211
212                     glob_offset++;
213
214                     /* Now we need to create another file entry */
215                     pl++;
216                     os_realloc(logf, (pl +2)*sizeof(logreader), log_config->config);
217                     logf = log_config->config;
218
219                     logf[pl].file = NULL;
220                     logf[pl].alias = NULL;
221                     logf[pl].logformat = NULL;
222                     logf[pl].fp = NULL;
223                     logf[pl].ffile = NULL;
224
225                     logf[pl +1].file = NULL;
226                     logf[pl +1].alias = NULL;
227                     logf[pl +1].logformat = NULL;
228                 }
229
230
231                 globfree(&g);
232             } else if (strchr(node[i]->content, '%'))
233             #else
234             if (strchr(node[i]->content, '%'))
235             #endif /* WIN32 */
236
237             /* We need the format file (based on date) */
238             {
239                 struct tm *p;
240                 time_t l_time = time(0);
241                 char lfile[OS_FLSIZE + 1];
242                 size_t ret;
243
244                 p = localtime(&l_time);
245
246                 lfile[OS_FLSIZE] = '\0';
247                 ret = strftime(lfile, OS_FLSIZE, node[i]->content, p);
248                 if (ret != 0) {
249                     os_strdup(node[i]->content, logf[pl].ffile);
250                 }
251
252                 os_strdup(node[i]->content, logf[pl].file);
253             }
254
255             /* Normal file */
256             else {
257                 os_strdup(node[i]->content, logf[pl].file);
258             }
259         }
260
261         /* Get log format */
262         else if (strcasecmp(node[i]->element, xml_localfile_logformat) == 0) {
263             os_strdup(node[i]->content, logf[pl].logformat);
264
265             if (strcmp(logf[pl].logformat, "syslog") == 0) {
266             } else if (strcmp(logf[pl].logformat, "generic") == 0) {
267             } else if (strcmp(logf[pl].logformat, "snort-full") == 0) {
268             } else if (strcmp(logf[pl].logformat, "snort-fast") == 0) {
269             } else if (strcmp(logf[pl].logformat, "apache") == 0) {
270             } else if (strcmp(logf[pl].logformat, "iis") == 0) {
271             } else if (strcmp(logf[pl].logformat, "squid") == 0) {
272             } else if (strcmp(logf[pl].logformat, "nmapg") == 0) {
273             } else if (strcmp(logf[pl].logformat, "mysql_log") == 0) {
274             } else if (strcmp(logf[pl].logformat, "ossecalert") == 0) {
275             } else if (strcmp(logf[pl].logformat, "mssql_log") == 0) {
276             } else if (strcmp(logf[pl].logformat, "postgresql_log") == 0) {
277             } else if (strcmp(logf[pl].logformat, "djb-multilog") == 0) {
278             } else if (strcmp(logf[pl].logformat, "syslog-pipe") == 0) {
279             } else if (strcmp(logf[pl].logformat, "command") == 0) {
280             } else if (strcmp(logf[pl].logformat, "full_command") == 0) {
281             } else if (strcmp(logf[pl].logformat, "audit") == 0) {
282             } else if (strncmp(logf[pl].logformat, "multi-line", 10) == 0) {
283                 int x = 0;
284                 logf[pl].logformat += 10;
285
286                 while (logf[pl].logformat[0] == ' ') {
287                     logf[pl].logformat++;
288                 }
289
290                 if (logf[pl].logformat[0] != ':') {
291                     merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
292                     return (OS_INVALID);
293                 }
294                 logf[pl].logformat++;
295
296                 while (*logf[pl].logformat == ' ') {
297                     logf[pl].logformat++;
298                 }
299
300                 while (logf[pl].logformat[x] >= '0' && logf[pl].logformat[x] <= '9') {
301                     x++;
302                 }
303
304                 while (logf[pl].logformat[x] == ' ') {
305                     x++;
306                 }
307
308                 if (logf[pl].logformat[x] != '\0') {
309                     merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
310                     return (OS_INVALID);
311                 }
312             } else if (strcmp(logf[pl].logformat, EVENTLOG) == 0) {
313             } else if (strcmp(logf[pl].logformat, EVENTCHANNEL) == 0) {
314             } else {
315                 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
316                 return (OS_INVALID);
317             }
318         } else if (strcasecmp(node[i]->element, xml_localfile_alias) == 0) {
319             os_strdup(node[i]->content, logf[pl].alias);
320         } else {
321             merror(XML_INVELEM, __local_name, node[i]->element);
322             return (OS_INVALID);
323         }
324
325         i++;
326     }
327
328     /* Validate glob entries */
329     if (glob_set) {
330         char *format;
331
332         /* Get log format */
333         if (logf[pl].logformat) {
334             format = logf[pl].logformat;
335         } else if (logf[glob_set - 1].logformat) {
336             format = logf[glob_set - 1].logformat;
337         } else {
338             merror(MISS_LOG_FORMAT, __local_name);
339             return (OS_INVALID);
340         }
341
342         /* The last entry is always null on glob */
343         pl--;
344
345         /* Set format for all entries */
346         for (i = (glob_set - 1); i <= pl; i++) {
347             /* Every entry must be valid */
348             if (!logf[i].file) {
349                 merror(MISS_FILE, __local_name);
350                 return (OS_INVALID);
351             }
352
353             if (logf[i].logformat == NULL) {
354                 logf[i].logformat = format;
355             }
356
357         }
358     }
359
360     /* Missing log format */
361     if (!logf[pl].logformat) {
362         merror(MISS_LOG_FORMAT, __local_name);
363         return (OS_INVALID);
364     }
365
366     /* Missing file */
367     if (!logf[pl].file) {
368         merror(MISS_FILE, __local_name);
369         return (OS_INVALID);
370     }
371
372     /* Verify a valid event log config */
373     if (strcmp(logf[pl].logformat, EVENTLOG) == 0) {
374         if ((strcmp(logf[pl].file, "Application") != 0) &&
375                 (strcmp(logf[pl].file, "System") != 0) &&
376                 (strcmp(logf[pl].file, "Security") != 0)) {
377             /* Invalid event log */
378             merror(NSTD_EVTLOG, __local_name, logf[pl].file);
379             return (0);
380         }
381     }
382
383     if ((strcmp(logf[pl].logformat, "command") == 0) ||
384             (strcmp(logf[pl].logformat, "full_command") == 0)) {
385         if (!logf[pl].command) {
386             merror("%s: ERROR: Missing 'command' argument. "
387                    "This option will be ignored.", __local_name);
388         }
389     }
390
391     return (0);
392 }
393