new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / logcollector / read_postgresql_log.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All rights 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 /* Read PostgreSQL logs */
11
12 #include "shared.h"
13 #include "logcollector.h"
14
15
16 /* Send pgsql message and check the return code */
17 static void __send_pgsql_msg(int pos, int drop_it, char *buffer)
18 {
19     debug2("%s: DEBUG: Reading PostgreSQL message: '%s'", ARGV0, buffer);
20     if (drop_it == 0) {
21         if (SendMSG(logr_queue, buffer, logff[pos].file, POSTGRESQL_MQ) < 0) {
22             merror(QUEUE_SEND, ARGV0);
23             if ((logr_queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
24                 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
25             }
26         }
27     }
28 }
29
30 /* Read PostgreSQL log files */
31 void *read_postgresql_log(int pos, int *rc, int drop_it)
32 {
33     size_t str_len = 0;
34     int need_clear = 0;
35     char *p;
36     char str[OS_MAXSTR + 1];
37     char buffer[OS_MAXSTR + 1];
38
39     /* Zero buffer and str */
40     buffer[0] = '\0';
41     buffer[OS_MAXSTR] = '\0';
42     str[OS_MAXSTR] = '\0';
43     *rc = 0;
44
45     /* Get new entry */
46     while (fgets(str, OS_MAXSTR - OS_LOG_HEADER, logff[pos].fp) != NULL) {
47         /* Get buffer size */
48         str_len = strlen(str);
49
50         /* Check str_len size. Very useless, but just to make sure.. */
51         if (str_len >= sizeof(buffer) - 2) {
52             str_len = sizeof(buffer) - 10;
53         }
54
55         /* Get the last occurrence of \n */
56         if ((p = strrchr(str, '\n')) != NULL) {
57             *p = '\0';
58
59             /* If need_clear is set, we just get the line and ignore it. */
60             if (need_clear) {
61                 need_clear = 0;
62                 continue;
63             }
64         } else {
65             need_clear = 1;
66         }
67
68 #ifdef WIN32
69         if ((p = strrchr(str, '\r')) != NULL) {
70             *p = '\0';
71         }
72
73         /* Look for empty string (only on Windows) */
74         if (str_len <= 1) {
75             continue;
76         }
77
78         /* Windows can have comment on their logs */
79         if (str[0] == '#') {
80             continue;
81         }
82 #endif
83
84         /* PostgreSQL messages have the following format:
85          * [2007-08-31 19:17:32.186 ADT] 192.168.2.99:db_name
86          */
87         if ((str_len > 32) &&
88                 (str[0] == '[') &&
89                 (str[5] == '-') &&
90                 (str[8] == '-') &&
91                 (str[11] == ' ') &&
92                 (str[14] == ':') &&
93                 (str[17] == ':') &&
94                 isdigit((int)str[1]) &&
95                 isdigit((int)str[12])) {
96
97             /* If the saved message is empty, set it and continue */
98             if (buffer[0] == '\0') {
99                 strncpy(buffer, str, str_len + 2);
100                 continue;
101             }
102
103             /* If not, send the saved one and store the new one for later */
104             else {
105                 __send_pgsql_msg(pos, drop_it, buffer);
106                 /* Store current one at the buffer */
107                 strncpy(buffer, str, str_len + 2);
108             }
109         }
110
111         /* Query logs can be in multiple lines
112          * They always start with a tab in the additional ones
113          */
114         else if ((str_len > 2) && (buffer[0] != '\0') &&
115                  (str[0] == '\t')) {
116             /* Size of the buffer */
117             size_t buffer_len = strlen(buffer);
118
119             p = str + 1;
120
121             /* Remove extra spaces and tabs */
122             while (*p == ' ' || *p == '\t') {
123                 p++;
124             }
125
126             /* Add additional message to the saved buffer */
127             if (sizeof(buffer) - buffer_len > str_len + 256) {
128                 /* Here we make sure that the size of the buffer
129                  * minus what was used (strlen) is greater than
130                  * the length of the received message.
131                  */
132                 buffer[buffer_len] = ' ';
133                 buffer[buffer_len + 1] = '\0';
134                 strncat(buffer, str, str_len + 3);
135             }
136         }
137
138         continue;
139     }
140
141     /* Send whatever is stored */
142     if (buffer[0] != '\0') {
143         __send_pgsql_msg(pos, drop_it, buffer);
144     }
145
146     return (NULL);
147 }
148