new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / logcollector / read_audit.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 "logcollector.h"
12
13 #define MAX_CACHE 16
14 #define MAX_HEADER 64
15
16 /* Compile message from cache and send through queue */
17 static void audit_send_msg(char **cache, int top, const char *file, int drop_it) {
18     int i;
19     size_t n = 0;
20     size_t z;
21     char message[OS_MAXSTR];
22
23     for (i = 0; i < top; i++) {
24         z = strlen(cache[i]);
25
26         if (n + z + 1 < OS_MAXSTR) {
27             if (n > 0)
28                 message[n++] = ' ';
29             
30             strncpy(message + n, cache[i], z);
31         }
32
33         n += z;
34         free(cache[i]);
35     }
36
37     if (!drop_it) {
38         message[n] = '\0';
39
40         if (SendMSG(logr_queue, message, file, LOCALFILE_MQ) < 0) {
41             merror(QUEUE_SEND, ARGV0);
42
43             if ((logr_queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
44                 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
45             }
46         }
47     }
48 }
49
50 void *read_audit(int pos, int *rc, int drop_it) {
51     char *cache[MAX_CACHE];
52     char header[MAX_HEADER] = { '\0' };
53     int icache = 0;
54     char buffer[OS_MAXSTR];
55     char *id;
56     char *p;
57     size_t z;
58     long offset = ftell(logff[pos].fp);
59     
60     if (offset < 0) {
61         merror(FTELL_ERROR, ARGV0, logff[pos].file, errno, strerror(errno));
62         return NULL;
63     }
64
65     *rc = 0;
66
67     while (fgets(buffer, OS_MAXSTR, logff[pos].fp)) {
68         if ((p = strchr(buffer, '\n')))
69             *p = '\0';
70         else {
71             if (strlen(buffer) == OS_MAXSTR - 1) {
72                 // Message too large, discard line
73                 while (fgets(buffer, OS_MAXSTR, logff[pos].fp) && !strchr(buffer, '\n'));
74             } else {
75                 debug1("%s: Message not complete. Trying again: '%s'", ARGV0, buffer);
76                 
77                 if (fseek(logff[pos].fp, offset, SEEK_SET) < 0) {
78                     merror(FSEEK_ERROR, ARGV0, logff[pos].file, errno, strerror(errno));
79                     break;
80                 }
81             }
82
83             break;
84         }
85
86         // Extract header: "type=\.* msg=audit(\d+.\d+:\d+):"
87
88         if (strncmp(buffer, "type=", 5) || !((id = strstr(buffer + 5, "msg=audit(")) && (p = strstr(id += 10, "): ")))) {
89             merror("%s: ERROR: discarding audit message because of invalid syntax", ARGV0);
90             break;
91         }
92         
93         z = p - id;
94
95         if (strncmp(id, header, z)) {
96             // Current message belongs to another event: send cached messages
97             if (icache > 0)
98                 audit_send_msg(cache, icache, logff[pos].file, drop_it);
99
100             // Store current event
101             *cache = strdup(buffer);
102             icache = 1;
103             strncpy(header, id, z < MAX_HEADER ? z : MAX_HEADER - 1);
104         } else {
105             // The header is the same: store
106             if (icache == MAX_CACHE)
107                 merror("%s: ERROR: discarding audit message because cache is full", ARGV0);
108             else
109                 cache[icache++] = strdup(buffer);
110         }
111     }
112
113     if (icache > 0)
114         audit_send_msg(cache, icache, logff[pos].file, drop_it);
115
116     return NULL;
117 }