1 /* Copyright (C) 2009 Trend Micro Inc.
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
13 #include <sys/types.h>
19 #define sleep(x) Sleep(x * 1000)
22 #ifdef INOTIFY_ENABLED
23 #include <sys/inotify.h>
24 #define OS_SIZE_6144 6144
25 #define OS_MAXSTR OS_SIZE_6144 /* Size for logs, sockets, etc */
34 #include "error_messages/error_messages.h"
37 int realtime_checksumfile(const char *file_name) __attribute__((nonnull));
40 /* Checksum of the realtime file being monitored */
41 int realtime_checksumfile(const char *file_name)
45 buf = (char *) OSHash_Get(syscheck.fp, file_name);
52 /* If it returns < 0, we have already alerted */
53 if (c_read_file(file_name, buf, c_sum) < 0) {
57 if (strcmp(c_sum, buf + 6) != 0) {
58 char alert_msg[OS_MAXSTR + 1];
60 alert_msg[OS_MAXSTR] = '\0';
63 snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
65 char *fullalert = NULL;
67 if (buf[5] == 's' || buf[5] == 'n') {
68 fullalert = seechanges_addfile(file_name);
70 snprintf(alert_msg, OS_MAXSTR, "%s %s\n%s", c_sum, file_name, fullalert);
74 snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
77 snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
80 send_syscheck_msg(alert_msg);
89 buf = strdup(file_name);
91 /* Find container directory */
93 while (c = strrchr(buf, '/'), c && c != buf) {
96 for (i = 0; syscheck.dir[i]; i++) {
97 if (strcmp(syscheck.dir[i], buf) == 0) {
98 debug1("%s: DEBUG: Scanning new file '%s' with options for directory '%s'.", ARGV0, file_name, buf);
99 read_dir(file_name, syscheck.opts[i], syscheck.filerestrict[i]);
104 if (syscheck.dir[i]) {
115 #ifdef INOTIFY_ENABLED
116 #include <sys/inotify.h>
118 #define REALTIME_MONITOR_FLAGS IN_MODIFY|IN_ATTRIB|IN_MOVED_FROM|IN_MOVED_TO|IN_CREATE|IN_DELETE|IN_DELETE_SELF
119 #define REALTIME_EVENT_SIZE (sizeof (struct inotify_event))
120 #define REALTIME_EVENT_BUFFER (2048 * (REALTIME_EVENT_SIZE + 16))
122 /* Start real time monitoring using inotify */
125 verbose("%s: INFO: Initializing real time file monitoring (not started).", ARGV0);
127 syscheck.realtime = (rtfim *) calloc(1, sizeof(rtfim));
128 if (syscheck.realtime == NULL) {
129 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
131 syscheck.realtime->dirtb = OSHash_Create();
132 syscheck.realtime->fd = -1;
134 #ifdef INOTIFY_ENABLED
135 syscheck.realtime->fd = inotify_init();
136 if (syscheck.realtime->fd < 0) {
137 merror("%s: ERROR: Unable to initialize inotify.", ARGV0);
145 /* Add a directory to real time checking */
146 int realtime_adddir(const char *dir)
148 if (!syscheck.realtime) {
152 /* Check if it is ready to use */
153 if (syscheck.realtime->fd < 0) {
158 if(syscheck.skip_nfs) {
159 short is_nfs = IsNFS(dir);
161 merror("%s: ERROR: %s NFS Directories do not support iNotify.", ARGV0, dir);
165 debug2("%s: DEBUG: syscheck.skip_nfs=%d, %s::is_nfs=%d", ARGV0, syscheck.skip_nfs, dir, is_nfs);
169 wd = inotify_add_watch(syscheck.realtime->fd,
171 REALTIME_MONITOR_FLAGS);
173 merror("%s: ERROR: Unable to add directory to real time "
174 "monitoring: '%s'. %d %s", ARGV0, dir, wd, strerror(errno));
178 snprintf(wdchar, 32, "%d", wd);
180 /* Entry not present */
181 if (!OSHash_Get(syscheck.realtime->dirtb, wdchar)) {
186 ErrorExit("%s: ERROR: Out of memory. Exiting.", ARGV0);
189 OSHash_Add(syscheck.realtime->dirtb, wdchar, ndir);
190 debug1("%s: DEBUG: Directory added for real time monitoring: "
191 "'%s'.", ARGV0, ndir);
199 /* Process events in the real time queue */
200 int realtime_process()
204 char buf[REALTIME_EVENT_BUFFER + 1];
205 struct inotify_event *event;
207 buf[REALTIME_EVENT_BUFFER] = '\0';
209 len = read(syscheck.realtime->fd, buf, REALTIME_EVENT_BUFFER);
211 merror("%s: ERROR: Unable to read from real time buffer.", ARGV0);
212 } else if (len > 0) {
214 while (i < (size_t) len) {
215 event = (struct inotify_event *) (void *) &buf[i];
219 char final_name[MAX_LINE + 1];
222 final_name[MAX_LINE] = '\0';
224 snprintf(wdchar, 32, "%d", event->wd);
226 snprintf(final_name, MAX_LINE, "%s/%s",
227 (char *)OSHash_Get(syscheck.realtime->dirtb, wdchar),
229 /* Need a sleep here to avoid triggering on vim edits
230 * (and finding the file removed)
234 realtime_checksumfile(final_name);
237 i += REALTIME_EVENT_SIZE + event->len;
245 typedef struct _win32rtfim {
250 TCHAR buffer[1228800];
253 int realtime_win32read(win32rtfim *rtlocald);
255 void CALLBACK RTCallBack(DWORD dwerror, DWORD dwBytes, LPOVERLAPPED overlap)
261 char final_path[MAX_LINE + 1];
262 win32rtfim *rtlocald;
263 PFILE_NOTIFY_INFORMATION pinfo;
264 TCHAR finalfile[MAX_PATH];
267 merror("%s: ERROR: real time call back called, but 0 bytes.", ARGV0);
268 rtlocald = OSHash_Get(syscheck.realtime->dirtb, "0");
270 realtime_win32read(rtlocald);
275 if (dwerror != ERROR_SUCCESS) {
276 merror("%s: ERROR: real time call back called, but error is set.",
281 /* Get hash to parse the data */
283 snprintf(wdchar, 32, "%d", (int)overlap->Offset);
284 rtlocald = OSHash_Get(syscheck.realtime->dirtb, wdchar);
285 if (rtlocald == NULL) {
286 merror("%s: ERROR: real time call back called, but hash is empty.",
292 pinfo = (PFILE_NOTIFY_INFORMATION) &rtlocald->buffer[offset];
293 offset += pinfo->NextEntryOffset;
295 lcount = WideCharToMultiByte(CP_ACP, 0, pinfo->FileName,
296 pinfo->FileNameLength / sizeof(WCHAR),
297 finalfile, MAX_PATH - 1, NULL, NULL);
298 finalfile[lcount] = TEXT('\0');
300 /* Change forward slashes to backslashes on finalfile */
301 ptfile = strchr(finalfile, '\\');
306 ptfile = strchr(ptfile, '\\');
309 final_path[MAX_LINE] = '\0';
310 snprintf(final_path, MAX_LINE, "%s/%s", rtlocald->dir, finalfile);
312 /* Check the change */
313 realtime_checksumfile(final_path);
314 } while (pinfo->NextEntryOffset != 0);
316 realtime_win32read(rtlocald);
323 verbose("%s: INFO: Initializing real time file monitoring (not started).", ARGV0);
325 os_calloc(1, sizeof(rtfim), syscheck.realtime);
326 syscheck.realtime->dirtb = (void *)OSHash_Create();
327 syscheck.realtime->fd = -1;
328 syscheck.realtime->evt = CreateEvent(NULL, TRUE, FALSE, NULL);
333 int realtime_win32read(win32rtfim *rtlocald)
337 rc = ReadDirectoryChangesW(rtlocald->h,
339 sizeof(rtlocald->buffer) / sizeof(TCHAR),
341 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SECURITY,
346 merror("%s: ERROR: Unable to set directory for monitoring: %s",
347 ARGV0, rtlocald->dir);
354 int realtime_adddir(const char *dir)
357 win32rtfim *rtlocald;
359 if (!syscheck.realtime) {
363 /* Maximum limit for realtime on Windows */
364 if (syscheck.realtime->fd > 256) {
365 merror("%s: ERROR: Unable to add directory to real time "
366 "monitoring: '%s' - Maximum size permitted.", ARGV0, dir);
370 os_calloc(1, sizeof(win32rtfim), rtlocald);
372 rtlocald->h = CreateFile(dir,
374 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
377 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
381 if (rtlocald->h == INVALID_HANDLE_VALUE ||
382 rtlocald->h == NULL) {
385 merror("%s: ERROR: Unable to add directory to real time "
386 "monitoring: '%s'.", ARGV0, dir);
390 rtlocald->overlap.Offset = ++syscheck.realtime->fd;
392 /* Set key for hash */
394 snprintf(wdchar, 32, "%d", (int)rtlocald->overlap.Offset);
396 if (OSHash_Get(syscheck.realtime->dirtb, wdchar)) {
397 merror("%s: ERROR: Entry already in the real time hash: %s",
399 CloseHandle(rtlocald->overlap.hEvent);
405 /* Add final elements to the hash */
406 os_strdup(dir, rtlocald->dir);
407 OSHash_Add(syscheck.realtime->dirtb, strdup(wdchar), rtlocald);
409 /* Add directory to be monitored */
410 realtime_win32read(rtlocald);
419 verbose("%s: ERROR: Unable to initialize real time file monitoring.", ARGV0);
424 int realtime_adddir(__attribute__((unused)) const char *dir)
429 int realtime_process()