izmjene licence
[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 alert_msg[OS_MAXSTR +1];
78              alert_msg[OS_MAXSTR] = '\0';
79              #ifdef WIN32
80              snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
81              #else
82              char *fullalert = NULL;
83              if(buf[5] == 's' || buf[5] == 'n')
84              {
85                  fullalert = seechanges_addfile(file_name);
86                  if(fullalert)
87                  {
88                     snprintf(alert_msg, OS_MAXSTR, "%s %s\n%s", c_sum, file_name, fullalert);
89                     free(fullalert);
90                     fullalert = NULL;
91                  }
92                  else
93                  {
94                      snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
95                  }
96              }
97              else
98              {
99                  snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
100              }
101              #endif
102              send_syscheck_msg(alert_msg);
103
104              return(1);
105          }
106
107          return(0);
108
109     }
110
111     return(0);
112 }
113
114
115
116
117 #ifdef USEINOTIFY
118 #include <sys/inotify.h>
119
120
121 #define REALTIME_MONITOR_FLAGS  IN_MODIFY|IN_ATTRIB|IN_MOVED_FROM|IN_MOVED_TO|IN_CREATE|IN_DELETE|IN_DELETE_SELF
122 #define REALTIME_EVENT_SIZE     (sizeof (struct inotify_event))
123 #define REALTIME_EVENT_BUFFER   (2048 * (REALTIME_EVENT_SIZE + 16))
124
125
126
127 /* Starts real time monitoring using inotify. */
128 int realtime_start()
129 {
130     verbose("%s: INFO: Initializing real time file monitoring (not started).", ARGV0);
131
132     syscheck.realtime = calloc(1, sizeof(rtfim));
133     if(syscheck.realtime == NULL)
134     {
135         ErrorExit(MEM_ERROR, ARGV0);
136     }
137     syscheck.realtime->dirtb = (void *)OSHash_Create();
138     syscheck.realtime->fd = -1;
139
140     #ifdef USEINOTIFY
141     syscheck.realtime->fd = inotify_init();
142     if(syscheck.realtime->fd < 0)
143     {
144         merror("%s: ERROR: Unable to initialize inotify.", ARGV0);
145         return(-1);
146     }
147     #endif
148
149     return(1);
150 }
151
152
153
154 /* Adds a directory to real time checking. */
155 int realtime_adddir(char *dir)
156 {
157     if(!syscheck.realtime)
158     {
159         realtime_start();
160     }
161
162
163     /* Checking if it is ready to use. */
164     if(syscheck.realtime->fd < 0)
165     {
166         return(-1);
167     }
168     else
169     {
170         int wd = 0;
171
172         wd = inotify_add_watch(syscheck.realtime->fd,
173                                dir,
174                                REALTIME_MONITOR_FLAGS);
175         if(wd < 0)
176         {
177             merror("%s: ERROR: Unable to add directory to real time "
178                    "monitoring: '%s'. %d %d", ARGV0, dir, wd, errno);
179         }
180         else
181         {
182             char wdchar[32 +1];
183             wdchar[32] = '\0';
184             snprintf(wdchar, 32, "%d", wd);
185
186             /* Entry not present. */
187             if(!OSHash_Get(syscheck.realtime->dirtb, wdchar))
188             {
189                 char *ndir;
190
191                 ndir = strdup(dir);
192                 if(ndir == NULL)
193                 {
194                     ErrorExit("%s: ERROR: Out of memory. Exiting.", ARGV0);
195                 }
196
197                 OSHash_Add(syscheck.realtime->dirtb, strdup(wdchar), ndir);
198                 debug1("%s: DEBUG: Directory added for real time monitoring: "
199                        "'%s'.", ARGV0, ndir);
200             }
201         }
202     }
203
204     return(1);
205 }
206
207
208 /* Process events in the real time queue. */
209 int realtime_process()
210 {
211     int len, i = 0;
212     char buf[REALTIME_EVENT_BUFFER +1];
213     struct inotify_event *event;
214
215     buf[REALTIME_EVENT_BUFFER] = '\0';
216
217
218     len = read(syscheck.realtime->fd, buf, REALTIME_EVENT_BUFFER);
219     if (len < 0)
220     {
221         merror("%s: ERROR: Unable to read from real time buffer.", ARGV0);
222     }
223     else if (len > 0)
224     {
225         while (i < len)
226         {
227             event = (struct inotify_event *) &buf[i];
228
229             if(event->len)
230             {
231                 char wdchar[32 +1];
232                 char final_name[MAX_LINE +1];
233
234                 wdchar[32] = '\0';
235                 final_name[MAX_LINE] = '\0';
236
237                 snprintf(wdchar, 32, "%d", event->wd);
238
239                 snprintf(final_name, MAX_LINE, "%s/%s",
240                          (char *)OSHash_Get(syscheck.realtime->dirtb, wdchar),
241                          event->name);
242                 realtime_checksumfile(final_name);
243             }
244
245             i += REALTIME_EVENT_SIZE + event->len;
246         }
247     }
248
249     return(0);
250 }
251
252
253
254 #elif WIN32
255 typedef struct _win32rtfim
256 {
257     HANDLE h;
258     OVERLAPPED overlap;
259
260     char *dir;
261     TCHAR buffer[12288];
262 }win32rtfim;
263
264 int realtime_win32read(win32rtfim *rtlocald);
265
266 void CALLBACK RTCallBack(DWORD dwerror, DWORD dwBytes, LPOVERLAPPED overlap)
267 {
268     int lcount;
269     size_t offset = 0;
270
271     char *ptfile;
272     char wdchar[32 +1];
273     char final_path[MAX_LINE +1];
274
275     win32rtfim *rtlocald;
276
277     PFILE_NOTIFY_INFORMATION pinfo;
278     TCHAR finalfile[MAX_PATH];
279
280     if(dwBytes == 0)
281     {
282         merror("%s: ERROR: real time call back called, but 0 bytes.", ARGV0);
283         return;
284     }
285
286     if(dwerror != ERROR_SUCCESS)
287     {
288         merror("%s: ERROR: real time call back called, but error is set.",
289                ARGV0);
290         return;
291     }
292
293
294     /* Getting hash to parse the data. */
295     wdchar[32] = '\0';
296     snprintf(wdchar, 32, "%d", (int)overlap->Offset);
297     rtlocald = OSHash_Get(syscheck.realtime->dirtb, wdchar);
298     if(rtlocald == NULL)
299     {
300         merror("%s: ERROR: real time call back called, but hash is empty.",
301                ARGV0);
302         return;
303     }
304
305
306
307     do
308     {
309         pinfo = (PFILE_NOTIFY_INFORMATION) &rtlocald->buffer[offset];
310         offset += pinfo->NextEntryOffset;
311
312         lcount = WideCharToMultiByte(CP_ACP, 0, pinfo->FileName,
313                                      pinfo->FileNameLength / sizeof(WCHAR),
314                                      finalfile, MAX_PATH - 1, NULL, NULL);
315         finalfile[lcount] = TEXT('\0');
316
317
318         /* Change forward slashes to backslashes on finalfile. */
319         ptfile = strchr(finalfile, '\\');
320         while(ptfile)
321         {
322             *ptfile = '/';
323             ptfile++;
324
325             ptfile = strchr(ptfile, '\\');
326         }
327
328         final_path[MAX_LINE] = '\0';
329         snprintf(final_path, MAX_LINE, "%s/%s", rtlocald->dir, finalfile);
330
331
332         /* Checking the change. */
333         realtime_checksumfile(final_path);
334
335
336         /*
337         if(pinfo->Action == FILE_ACTION_ADDED)
338         else if(pinfo->Action == FILE_ACTION_REMOVED)
339         else if(pinfo->Action == FILE_ACTION_MODIFIED)
340         else if(pinfo->Action == FILE_ACTION_RENAMED_OLD_NAME)
341         else if(pinfo->Action == FILE_ACTION_RENAMED_NEW_NAME)
342         else
343         */
344
345     }while(pinfo->NextEntryOffset != 0);
346
347
348     realtime_win32read(rtlocald);
349
350
351     return;
352 }
353
354
355
356 int realtime_start()
357 {
358     verbose("%s: INFO: Initializing real time file monitoring (not started).", ARGV0);
359
360     os_calloc(1, sizeof(rtfim), syscheck.realtime);
361     syscheck.realtime->dirtb = (void *)OSHash_Create();
362     syscheck.realtime->fd = -1;
363     syscheck.realtime->evt = CreateEvent(NULL, TRUE, FALSE, NULL);
364     return(0);
365 }
366
367 int realtime_win32read(win32rtfim *rtlocald)
368 {
369     int rc;
370
371     rc = ReadDirectoryChangesW(rtlocald->h,
372                                rtlocald->buffer,
373                                sizeof(rtlocald->buffer) / sizeof(TCHAR),
374                                TRUE,
375                                FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE,
376                                0,
377                                &rtlocald->overlap,
378                                RTCallBack);
379     if(rc == 0)
380     {
381         merror("%s: ERROR: Unable to set directory for monitoring: %s",
382                ARGV0, rtlocald->dir);
383         sleep(2);
384     }
385
386     return(0);
387 }
388
389 int realtime_adddir(char *dir)
390 {
391     char wdchar[32 +1];
392     win32rtfim *rtlocald;
393
394
395     if(!syscheck.realtime)
396     {
397         realtime_start();
398     }
399
400
401     /* Maximum limit for realtime on Windows. */
402     if(syscheck.realtime->fd > 256)
403     {
404         merror("%s: ERROR: Unable to add directory to real time "
405                "monitoring: '%s' - Maximum size permitted.", ARGV0, dir);
406         return(0);
407     }
408
409
410     os_calloc(1, sizeof(win32rtfim), rtlocald);
411
412
413     rtlocald->h = CreateFile(dir,
414                              FILE_LIST_DIRECTORY,
415                              FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
416                              NULL,
417                              OPEN_EXISTING,
418                              FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED,
419                              NULL);
420
421
422     if(rtlocald->h == INVALID_HANDLE_VALUE ||
423        rtlocald->h == NULL)
424     {
425         free(rtlocald);
426         rtlocald = NULL;
427         merror("%s: ERROR: Unable to add directory to real time "
428                "monitoring: '%s'.", ARGV0, dir);
429         return(0);
430     }
431
432     rtlocald->overlap.Offset = ++syscheck.realtime->fd;
433
434
435
436     /* Setting key for hash. */
437     wdchar[32] = '\0';
438     snprintf(wdchar, 32, "%d", (int)rtlocald->overlap.Offset);
439
440
441     if(OSHash_Get(syscheck.realtime->dirtb, wdchar))
442     {
443         merror("%s: ERROR: Entry already in the real time hash: %s",
444                ARGV0, wdchar);
445         CloseHandle(rtlocald->overlap.hEvent);
446         free(rtlocald);
447         rtlocald = NULL;
448         return(0);
449     }
450
451
452     /* Adding final elements to the hash. */
453     os_strdup(dir, rtlocald->dir);
454
455     OSHash_Add(syscheck.realtime->dirtb, strdup(wdchar), rtlocald);
456
457
458     /* Adding directory to be monitored. */
459     realtime_win32read(rtlocald);
460
461
462     return(1);
463 }
464
465
466
467
468
469 #else
470 int realtime_start()
471 {
472     verbose("%s: ERROR: Unable to initalize real time file monitoring.", ARGV0);
473     return(0);
474 }
475
476 int realtime_adddir(char *dir)
477 {
478     return(0);
479 }
480
481 int realtime_process()
482 {
483     return(0);
484 }
485
486 #endif
487 /* EOF */