1 /* Copyright (C) 2009 Trend Micro Inc.
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
11 #include "localfile-config.h"
15 int Read_Localfile(XML_NODE node, void *d1, __attribute__((unused)) void *d2)
19 unsigned int glob_set = 0;
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";
34 logreader_config *log_config;
36 log_config = (logreader_config *)d1;
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;
43 logf[0].command = NULL;
45 logf[0].logformat = NULL;
49 logf[1].command = NULL;
51 logf[1].logformat = NULL;
55 logf = log_config->config;
56 while (logf[pl].file != NULL) {
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;
72 logf[pl].command = NULL;
73 logf[pl].alias = NULL;
74 logf[pl].logformat = NULL;
76 logf[pl].query = NULL;
78 logf[pl].ffile = NULL;
79 logf[pl].djb_program_name = NULL;
83 /* Search for entries related to files */
86 if (!node[i]->element) {
87 merror(XML_ELEMNULL, __local_name);
89 } else if (!node[i]->content) {
90 merror(XML_VALUENULL, __local_name, node[i]->element);
92 } else if (strcmp(node[i]->element, xml_localfile_future) == 0) {
93 if (strcmp(node[i]->content, "yes") == 0) {
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);
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;
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) {
117 if(strcmp(node[i]->content, "hourly") == 0)
121 else if(strcmp(node[i]->content, "daily") == 0)
123 logf[pl].ign = 86400;
128 if (!OS_StrIsNum(node[i]->content)) {
129 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
133 logf[pl].ign = atoi(node[i]->content);
135 } else if (strcmp(node[i]->element, xml_localfile_location) == 0) {
137 /* Expand variables on Windows */
138 if (strchr(node[i]->content, '%')) {
139 int expandreturn = 0;
140 char newfile[OS_MAXSTR + 1];
142 newfile[OS_MAXSTR] = '\0';
143 expandreturn = ExpandEnvironmentStrings(node[i]->content,
146 if ((expandreturn > 0) && (expandreturn < OS_MAXSTR)) {
147 free(node[i]->content);
149 os_strdup(newfile, node[i]->content);
155 * We will call this file multiple times until
156 * there is no one else available.
158 #ifndef WIN32 /* No windows support for glob */
159 if (strchr(node[i]->content, '*') ||
160 strchr(node[i]->content, '?') ||
161 strchr(node[i]->content, '[')) {
164 /* Setting to the first entry of the glob */
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);
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);
188 while(g.gl_pathv[glob_offset] != NULL)
190 /* Check for strftime on globs too */
191 if (strchr(g.gl_pathv[glob_offset], '%')) {
193 time_t l_time = time(0);
194 char lfile[OS_FLSIZE + 1];
197 p = localtime(&l_time);
199 lfile[OS_FLSIZE] = '\0';
200 ret = strftime(lfile, OS_FLSIZE, g.gl_pathv[glob_offset], p);
202 merror(PARSE_ERROR, __local_name, g.gl_pathv[glob_offset]);
206 os_strdup(g.gl_pathv[glob_offset], logf[pl].ffile);
207 os_strdup(g.gl_pathv[glob_offset], logf[pl].file);
209 os_strdup(g.gl_pathv[glob_offset], logf[pl].file);
214 /* Now we need to create another file entry */
216 os_realloc(logf, (pl +2)*sizeof(logreader), log_config->config);
217 logf = log_config->config;
219 logf[pl].file = NULL;
220 logf[pl].alias = NULL;
221 logf[pl].logformat = NULL;
223 logf[pl].ffile = NULL;
225 logf[pl +1].file = NULL;
226 logf[pl +1].alias = NULL;
227 logf[pl +1].logformat = NULL;
232 } else if (strchr(node[i]->content, '%'))
234 if (strchr(node[i]->content, '%'))
237 /* We need the format file (based on date) */
240 time_t l_time = time(0);
241 char lfile[OS_FLSIZE + 1];
244 p = localtime(&l_time);
246 lfile[OS_FLSIZE] = '\0';
247 ret = strftime(lfile, OS_FLSIZE, node[i]->content, p);
249 os_strdup(node[i]->content, logf[pl].ffile);
252 os_strdup(node[i]->content, logf[pl].file);
257 os_strdup(node[i]->content, logf[pl].file);
262 else if (strcasecmp(node[i]->element, xml_localfile_logformat) == 0) {
263 os_strdup(node[i]->content, logf[pl].logformat);
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) {
284 logf[pl].logformat += 10;
286 while (logf[pl].logformat[0] == ' ') {
287 logf[pl].logformat++;
290 if (logf[pl].logformat[0] != ':') {
291 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
294 logf[pl].logformat++;
296 while (*logf[pl].logformat == ' ') {
297 logf[pl].logformat++;
300 while (logf[pl].logformat[x] >= '0' && logf[pl].logformat[x] <= '9') {
304 while (logf[pl].logformat[x] == ' ') {
308 if (logf[pl].logformat[x] != '\0') {
309 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
312 } else if (strcmp(logf[pl].logformat, EVENTLOG) == 0) {
313 } else if (strcmp(logf[pl].logformat, EVENTCHANNEL) == 0) {
315 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
318 } else if (strcasecmp(node[i]->element, xml_localfile_alias) == 0) {
319 os_strdup(node[i]->content, logf[pl].alias);
321 merror(XML_INVELEM, __local_name, node[i]->element);
328 /* Validate glob entries */
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;
338 merror(MISS_LOG_FORMAT, __local_name);
342 /* The last entry is always null on glob */
345 /* Set format for all entries */
346 for (i = (glob_set - 1); i <= pl; i++) {
347 /* Every entry must be valid */
349 merror(MISS_FILE, __local_name);
353 if (logf[i].logformat == NULL) {
354 logf[i].logformat = format;
360 /* Missing log format */
361 if (!logf[pl].logformat) {
362 merror(MISS_LOG_FORMAT, __local_name);
367 if (!logf[pl].file) {
368 merror(MISS_FILE, __local_name);
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);
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);