Imported Upstream version 2.7
[ossec-hids.git] / src / syscheckd / run_realtime.c
1 /* @(#) $Id: ./src/syscheckd/run_realtime.c, 2011/09/08 dcid Exp $
2  */
3
4 /* Copyright (C) 2009 Trend Micro Inc.
5  * All right reserved.
6  *
7  * This program is a free software; you can redistribute it
8  * and/or modify it under the terms of the GNU General Public
9  * License (version 2) as published by the FSF - Free Software
10  * Foundation
11  */
12
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <limits.h>
20 #include <errno.h>
21
22
23 #ifdef WIN32
24 #include <windows.h>
25 #include <winsock.h>
26 #include <io.h>
27
28 #define sleep(x) Sleep(x * 1000)
29 #define os_calloc(x,y,z) (z = calloc(x,y))?(void)1:ErrorExit(MEM_ERROR, ARGV0)
30 #define os_strdup(x,y) (y = strdup(x))?(void)1:ErrorExit(MEM_ERROR, ARGV0)
31 #endif
32
33
34 #include "hash_op.h"
35 #include "debug_op.h"
36 #include "syscheck.h"
37 #include "error_messages/error_messages.h"
38
39
40 #ifdef USEINOTIFY
41 #include <sys/inotify.h>
42 #define OS_SIZE_6144    6144
43 #define OS_MAXSTR       OS_SIZE_6144    /* Size for logs, sockets, etc */
44 #else
45 #include "shared.h"
46 #endif
47
48
49
50 /** Global functions for all realtime options. **/
51 int c_read_file(char *file_name, char *oldsum, char *newsum);
52
53
54 /* Checking sum of the realtime file being monitored. */
55 int realtime_checksumfile(char *file_name)
56 {
57     char *buf;
58
59     buf = OSHash_Get(syscheck.fp, file_name);
60     if(buf != NULL)
61     {
62         char c_sum[256 +2];
63
64         c_sum[0] = '\0';
65         c_sum[255] = '\0';
66
67
68          /* If it returns < 0, we will already have alerted. */
69          if(c_read_file(file_name, buf, c_sum) < 0)
70          {
71              return(0);
72          }
73
74
75          if(strcmp(c_sum, buf+6) != 0)
76          {
77              char *fullalert = NULL;
78              char alert_msg[OS_MAXSTR +1];
79              alert_msg[OS_MAXSTR] = '\0';
80              if(buf[5] == 's' || buf[5] == 'n')
81              {
82                  fullalert = seechanges_addfile(file_name);
83                  if(fullalert)
84                  {
85                     snprintf(alert_msg, OS_MAXSTR, "%s %s\n%s", c_sum, file_name, fullalert);
86                     free(fullalert);
87                     fullalert = NULL;
88                  }
89                  else
90                  {
91                      snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
92                  }
93              }
94              else
95              {
96                  snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
97              }
98              send_syscheck_msg(alert_msg);
99
100              return(1);
101          }
102
103          return(0);
104
105     }
106
107     return(0);
108 }
109
110
111
112
113 #ifdef USEINOTIFY
114 #include <sys/inotify.h>
115
116
117 #define REALTIME_MONITOR_FLAGS  IN_MODIFY|IN_ATTRIB|IN_MOVED_FROM|IN_MOVED_TO|IN_CREATE|IN_DELETE|IN_DELETE_SELF
118 #define REALTIME_EVENT_SIZE     (sizeof (struct inotify_event))
119 #define REALTIME_EVENT_BUFFER   (2048 * (REALTIME_EVENT_SIZE + 16))
120
121
122
123 /* Starts real time monitoring using inotify. */
124 int realtime_start()
125 {
126     verbose("%s: INFO: Initializing real time file monitoring (not started).", ARGV0);
127
128     syscheck.realtime = calloc(1, sizeof(rtfim));
129     if(syscheck.realtime == NULL)
130     {
131         ErrorExit(MEM_ERROR, ARGV0);
132     }
133     syscheck.realtime->dirtb = (void *)OSHash_Create();
134     syscheck.realtime->fd = -1;
135
136     #ifdef USEINOTIFY
137     syscheck.realtime->fd = inotify_init();
138     if(syscheck.realtime->fd < 0)
139     {
140         merror("%s: ERROR: Unable to initialize inotify.", ARGV0);
141         return(-1);
142     }
143     #endif
144
145     return(1);
146 }
147
148
149
150 /* Adds a directory to real time checking. */
151 int realtime_adddir(char *dir)
152 {
153     if(!syscheck.realtime)
154     {
155         realtime_start();
156     }
157
158
159     /* Checking if it is ready to use. */
160     if(syscheck.realtime->fd < 0)
161     {
162         return(-1);
163     }
164     else
165     {
166         int wd = 0;
167
168         wd = inotify_add_watch(syscheck.realtime->fd,
169                                dir,
170                                REALTIME_MONITOR_FLAGS);
171         if(wd < 0)
172         {
173             merror("%s: ERROR: Unable to add directory to real time "
174                    "monitoring: '%s'. %d %d", ARGV0, dir, wd, errno);
175         }
176         else
177         {
178             char wdchar[32 +1];
179             wdchar[32] = '\0';
180             snprintf(wdchar, 32, "%d", wd);
181
182             /* Entry not present. */
183             if(!OSHash_Get(syscheck.realtime->dirtb, wdchar))
184             {
185                 char *ndir;
186
187                 ndir = strdup(dir);
188                 if(ndir == NULL)
189                 {
190                     ErrorExit("%s: ERROR: Out of memory. Exiting.", ARGV0);
191                 }
192
193                 OSHash_Add(syscheck.realtime->dirtb, strdup(wdchar), ndir);
194                 debug1("%s: DEBUG: Directory added for real time monitoring: "
195                        "'%s'.", ARGV0, ndir);
196             }
197         }
198     }
199
200     return(1);
201 }
202
203
204 /* Process events in the real time queue. */
205 int realtime_process()
206 {
207     int len, i = 0;
208     char buf[REALTIME_EVENT_BUFFER +1];
209     struct inotify_event *event;
210
211     buf[REALTIME_EVENT_BUFFER] = '\0';
212
213
214     len = read(syscheck.realtime->fd, buf, REALTIME_EVENT_BUFFER);
215     if (len < 0)
216     {
217         merror("%s: ERROR: Unable to read from real time buffer.", ARGV0);
218     }
219     else if (len > 0)
220     {
221         while (i < len)
222         {
223             event = (struct inotify_event *) &buf[i];
224
225             if(event->len)
226             {
227                 char wdchar[32 +1];
228                 char final_name[MAX_LINE +1];
229
230                 wdchar[32] = '\0';
231                 final_name[MAX_LINE] = '\0';
232
233                 snprintf(wdchar, 32, "%d", event->wd);
234
235                 snprintf(final_name, MAX_LINE, "%s/%s",
236                          (char *)OSHash_Get(syscheck.realtime->dirtb, wdchar),
237                          event->name);
238                 realtime_checksumfile(final_name);
239             }
240
241             i += REALTIME_EVENT_SIZE + event->len;
242         }
243     }
244
245     return(0);
246 }
247
248
249
250 #elif WIN32
251 typedef struct _win32rtfim
252 {
253     HANDLE h;
254     OVERLAPPED overlap;
255
256     char *dir;
257     TCHAR buffer[12288];
258 }win32rtfim;
259
260 int realtime_win32read(win32rtfim *rtlocald);
261
262 void CALLBACK RTCallBack(DWORD dwerror, DWORD dwBytes, LPOVERLAPPED overlap)
263 {
264     int lcount;
265     size_t offset = 0;
266
267     char *ptfile;
268     char wdchar[32 +1];
269     char final_path[MAX_LINE +1];
270
271     win32rtfim *rtlocald;
272
273     PFILE_NOTIFY_INFORMATION pinfo;
274     TCHAR finalfile[MAX_PATH];
275
276     if(dwBytes == 0)
277     {
278         merror("%s: ERROR: real time call back called, but 0 bytes.", ARGV0);
279         return;
280     }
281
282     if(dwerror != ERROR_SUCCESS)
283     {
284         merror("%s: ERROR: real time call back called, but error is set.",
285                ARGV0);
286         return;
287     }
288
289
290     /* Getting hash to parse the data. */
291     wdchar[32] = '\0';
292     snprintf(wdchar, 32, "%d", (int)overlap->Offset);
293     rtlocald = OSHash_Get(syscheck.realtime->dirtb, wdchar);
294     if(rtlocald == NULL)
295     {
296         merror("%s: ERROR: real time call back called, but hash is empty.",
297                ARGV0);
298         return;
299     }
300
301
302
303     do
304     {
305         pinfo = (PFILE_NOTIFY_INFORMATION) &rtlocald->buffer[offset];
306         offset += pinfo->NextEntryOffset;
307
308         lcount = WideCharToMultiByte(CP_ACP, 0, pinfo->FileName,
309                                      pinfo->FileNameLength / sizeof(WCHAR),
310                                      finalfile, MAX_PATH - 1, NULL, NULL);
311         finalfile[lcount] = TEXT('\0');
312
313
314         /* Change forward slashes to backslashes on finalfile. */
315         ptfile = strchr(finalfile, '\\');
316         while(ptfile)
317         {
318             *ptfile = '/';
319             ptfile++;
320
321             ptfile = strchr(ptfile, '\\');
322         }
323
324         final_path[MAX_LINE] = '\0';
325         snprintf(final_path, MAX_LINE, "%s/%s", rtlocald->dir, finalfile);
326
327
328         /* Checking the change. */
329         realtime_checksumfile(final_path);
330
331
332         /*
333         if(pinfo->Action == FILE_ACTION_ADDED)
334         else if(pinfo->Action == FILE_ACTION_REMOVED)
335         else if(pinfo->Action == FILE_ACTION_MODIFIED)
336         else if(pinfo->Action == FILE_ACTION_RENAMED_OLD_NAME)
337         else if(pinfo->Action == FILE_ACTION_RENAMED_NEW_NAME)
338         else
339         */
340
341     }while(pinfo->NextEntryOffset != 0);
342
343
344     realtime_win32read(rtlocald);
345
346
347     return;
348 }
349
350
351
352 int realtime_start()
353 {
354     verbose("%s: INFO: Initializing real time file monitoring (not started).", ARGV0);
355
356     os_calloc(1, sizeof(rtfim), syscheck.realtime);
357     syscheck.realtime->dirtb = (void *)OSHash_Create();
358     syscheck.realtime->fd = -1;
359     syscheck.realtime->evt = CreateEvent(NULL, TRUE, FALSE, NULL);
360     return(0);
361 }
362
363 int realtime_win32read(win32rtfim *rtlocald)
364 {
365     int rc;
366
367     rc = ReadDirectoryChangesW(rtlocald->h,
368                                rtlocald->buffer,
369                                sizeof(rtlocald->buffer) / sizeof(TCHAR),
370                                TRUE,
371                                FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE,
372                                0,
373                                &rtlocald->overlap,
374                                RTCallBack);
375     if(rc == 0)
376     {
377         merror("%s: ERROR: Unable to set directory for monitoring: %s",
378                ARGV0, rtlocald->dir);
379         sleep(2);
380     }
381
382     return(0);
383 }
384
385 int realtime_adddir(char *dir)
386 {
387     char wdchar[32 +1];
388     win32rtfim *rtlocald;
389
390
391     if(!syscheck.realtime)
392     {
393         realtime_start();
394     }
395
396
397     /* Maximum limit for realtime on Windows. */
398     if(syscheck.realtime->fd > 256)
399     {
400         merror("%s: ERROR: Unable to add directory to real time "
401                "monitoring: '%s' - Maximum size permitted.", ARGV0, dir);
402         return(0);
403     }
404
405
406     os_calloc(1, sizeof(win32rtfim), rtlocald);
407
408
409     rtlocald->h = CreateFile(dir,
410                              FILE_LIST_DIRECTORY,
411                              FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
412                              NULL,
413                              OPEN_EXISTING,
414                              FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED,
415                              NULL);
416
417
418     if(rtlocald->h == INVALID_HANDLE_VALUE ||
419        rtlocald->h == NULL)
420     {
421         free(rtlocald);
422         rtlocald = NULL;
423         merror("%s: ERROR: Unable to add directory to real time "
424                "monitoring: '%s'.", ARGV0, dir);
425         return(0);
426     }
427
428     rtlocald->overlap.Offset = ++syscheck.realtime->fd;
429
430
431
432     /* Setting key for hash. */
433     wdchar[32] = '\0';
434     snprintf(wdchar, 32, "%d", (int)rtlocald->overlap.Offset);
435
436
437     if(OSHash_Get(syscheck.realtime->dirtb, wdchar))
438     {
439         merror("%s: ERROR: Entry already in the real time hash: %s",
440                ARGV0, wdchar);
441         CloseHandle(rtlocald->overlap.hEvent);
442         free(rtlocald);
443         rtlocald = NULL;
444         return(0);
445     }
446
447
448     /* Adding final elements to the hash. */
449     os_strdup(dir, rtlocald->dir);
450
451     OSHash_Add(syscheck.realtime->dirtb, strdup(wdchar), rtlocald);
452
453
454     /* Adding directory to be monitored. */
455     realtime_win32read(rtlocald);
456
457
458     return(1);
459 }
460
461
462
463
464
465 #else
466 int realtime_start()
467 {
468     verbose("%s: ERROR: Unable to initalize real time file monitoring.", ARGV0);
469     return(0);
470 }
471
472 int realtime_adddir(char *dir)
473 {
474     return(0);
475 }
476
477 int realtime_process()
478 {
479     return(0);
480 }
481
482 #endif
483 /* EOF */