new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / analysisd / decoders / rootcheck.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 /* Rootcheck decoder */
11
12 #include "config.h"
13 #include "os_regex/os_regex.h"
14 #include "eventinfo.h"
15 #include "alerts/alerts.h"
16 #include "decoder.h"
17
18 #define ROOTCHECK_DIR    "/queue/rootcheck"
19
20 /* Local variables */
21 static char *rk_agent_ips[MAX_AGENTS];
22 static FILE *rk_agent_fps[MAX_AGENTS];
23 static int rk_err;
24
25 /* Rootcheck decoder */
26 static OSDecoderInfo *rootcheck_dec = NULL;
27
28
29 /* Initialize the necessary information to process the rootcheck information */
30 void RootcheckInit()
31 {
32     int i = 0;
33
34     rk_err = 0;
35
36     for (; i < MAX_AGENTS; i++) {
37         rk_agent_ips[i] = NULL;
38         rk_agent_fps[i] = NULL;
39     }
40
41     /* Zero decoder */
42     os_calloc(1, sizeof(OSDecoderInfo), rootcheck_dec);
43     rootcheck_dec->id = getDecoderfromlist(ROOTCHECK_MOD);
44     rootcheck_dec->type = OSSEC_RL;
45     rootcheck_dec->name = ROOTCHECK_MOD;
46     rootcheck_dec->fts = 0;
47
48     debug1("%s: RootcheckInit completed.", ARGV0);
49
50     return;
51 }
52
53 /* Return the file pointer to be used */
54 static FILE *RK_File(const char *agent, int *agent_id)
55 {
56     int i = 0;
57     char rk_buf[OS_SIZE_1024 + 1];
58
59     while (rk_agent_ips[i] != NULL) {
60         if (strcmp(rk_agent_ips[i], agent) == 0) {
61             /* Pointing to the beginning of the file */
62             fseek(rk_agent_fps[i], 0, SEEK_SET);
63             *agent_id = i;
64             return (rk_agent_fps[i]);
65         }
66
67         i++;
68     }
69
70     /* If here, our agent wasn't found */
71     rk_agent_ips[i] = strdup(agent);
72
73     if (rk_agent_ips[i] != NULL) {
74         snprintf(rk_buf, OS_SIZE_1024, "%s/%s", ROOTCHECK_DIR, agent);
75
76         /* r+ to read and write. Do not truncate */
77         rk_agent_fps[i] = fopen(rk_buf, "r+");
78         if (!rk_agent_fps[i]) {
79             /* Try opening with a w flag, file probably does not exist */
80             rk_agent_fps[i] = fopen(rk_buf, "w");
81             if (rk_agent_fps[i]) {
82                 fclose(rk_agent_fps[i]);
83                 rk_agent_fps[i] = fopen(rk_buf, "r+");
84             }
85         }
86         if (!rk_agent_fps[i]) {
87             merror(FOPEN_ERROR, ARGV0, rk_buf, errno, strerror(errno));
88
89             free(rk_agent_ips[i]);
90             rk_agent_ips[i] = NULL;
91
92             return (NULL);
93         }
94
95         /* Return the opened pointer (the beginning of it) */
96         fseek(rk_agent_fps[i], 0, SEEK_SET);
97         *agent_id = i;
98         return (rk_agent_fps[i]);
99     }
100
101     else {
102         merror(MEM_ERROR, ARGV0, errno, strerror(errno));
103         return (NULL);
104     }
105
106     return (NULL);
107 }
108
109 /* Special decoder for rootcheck
110  * Not using the default rendering tools for simplicity
111  * and to be less resource intensive
112  */
113 int DecodeRootcheck(Eventinfo *lf)
114 {
115     int agent_id;
116
117     char *tmpstr;
118     char rk_buf[OS_SIZE_2048 + 1];
119
120     FILE *fp;
121
122     fpos_t fp_pos;
123
124     /* Zero rk_buf */
125     rk_buf[0] = '\0';
126     rk_buf[OS_SIZE_2048] = '\0';
127
128     fp = RK_File(lf->location, &agent_id);
129
130     if (!fp) {
131         merror("%s: Error handling rootcheck database.", ARGV0);
132         rk_err++;
133
134         return (0);
135     }
136
137     /* Get initial position */
138     if (fgetpos(fp, &fp_pos) == -1) {
139         merror("%s: Error handling rootcheck database (fgetpos).", ARGV0);
140         return (0);
141     }
142
143
144     /* Reads the file and search for a possible entry */
145     while (fgets(rk_buf, OS_SIZE_2048 - 1, fp) != NULL) {
146         /* Ignore blank lines and lines with a comment */
147         if (rk_buf[0] == '\n' || rk_buf[0] == '#') {
148             if (fgetpos(fp, &fp_pos) == -1) {
149                 merror("%s: Error handling rootcheck database "
150                        "(fgetpos2).", ARGV0);
151                 return (0);
152             }
153             continue;
154         }
155
156         /* Remove newline */
157         tmpstr = strchr(rk_buf, '\n');
158         if (tmpstr) {
159             *tmpstr = '\0';
160         }
161
162         /* Old format without the time stamps */
163         if (rk_buf[0] != '!') {
164             /* Cannot use strncmp to avoid errors with crafted files */
165             if (strcmp(lf->log, rk_buf) == 0) {
166                 rootcheck_dec->fts = 0;
167                 lf->decoder_info = rootcheck_dec;
168                 return (1);
169             }
170         }
171         /* New format */
172         else {
173             /* Going past time: !1183431603!1183431603  (last, first seen) */
174             tmpstr = rk_buf + 23;
175
176             /* Matches, we need to upgrade last time saw */
177             if (strcmp(lf->log, tmpstr) == 0) {
178                 if(fsetpos(fp, &fp_pos)) {
179                     merror("%s: Error handling rootcheck database "
180                            "(fsetpos).", ARGV0);
181                     return (0);
182                 }
183                 fprintf(fp, "!%ld", (long int)lf->time);
184                 rootcheck_dec->fts = 0;
185                 lf->decoder_info = rootcheck_dec;
186                 return (1);
187             }
188         }
189
190         /* Get current position */
191         if (fgetpos(fp, &fp_pos) == -1) {
192             merror("%s: Error handling rootcheck database (fgetpos3).", ARGV0);
193             return (0);
194         }
195     }
196
197     /* Add the new entry at the end of the file */
198     fseek(fp, 0, SEEK_END);
199     fprintf(fp, "!%ld!%ld %s\n", (long int)lf->time, (long int)lf->time, lf->log);
200     fflush(fp);
201
202     rootcheck_dec->fts = 0;
203     rootcheck_dec->fts |= FTS_DONE;
204     lf->decoder_info = rootcheck_dec;
205     return (1);
206 }
207