new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / syscheckd / run_realtime.c
old mode 100755 (executable)
new mode 100644 (file)
index 20d8fb2..575b97c
@@ -1,6 +1,3 @@
-/* @(#) $Id: ./src/syscheckd/run_realtime.c, 2011/09/08 dcid Exp $
- */
-
 /* Copyright (C) 2009 Trend Micro Inc.
  * All right reserved.
  *
@@ -10,7 +7,6 @@
  * Foundation
  */
 
-
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <limits.h>
 #include <errno.h>
 
-
 #ifdef WIN32
-#include <windows.h>
-#include <winsock.h>
-#include <io.h>
-
 #define sleep(x) Sleep(x * 1000)
-#define os_calloc(x,y,z) (z = calloc(x,y))?(void)1:ErrorExit(MEM_ERROR, ARGV0)
-#define os_strdup(x,y) (y = strdup(x))?(void)1:ErrorExit(MEM_ERROR, ARGV0)
 #endif
 
-
-#include "hash_op.h"
-#include "debug_op.h"
-#include "syscheck.h"
-#include "error_messages/error_messages.h"
-
-
-#ifdef USEINOTIFY
+#ifdef INOTIFY_ENABLED
 #include <sys/inotify.h>
 #define OS_SIZE_6144    6144
 #define OS_MAXSTR       OS_SIZE_6144    /* Size for logs, sockets, etc */
 #include "shared.h"
 #endif
 
+#include "fs_op.h"
+#include "hash_op.h"
+#include "debug_op.h"
+#include "syscheck.h"
+#include "error_messages/error_messages.h"
 
-
-/** Global functions for all realtime options. **/
-int c_read_file(char *file_name, char *oldsum, char *newsum);
+/* Prototypes */
+int realtime_checksumfile(const char *file_name) __attribute__((nonnull));
 
 
-/* Checking sum of the realtime file being monitored. */
-int realtime_checksumfile(char *file_name)
+/* Checksum of the realtime file being monitored */
+int realtime_checksumfile(const char *file_name)
 {
     char *buf;
 
-    buf = OSHash_Get(syscheck.fp, file_name);
-    if(buf != NULL)
-    {
-        char c_sum[256 +2];
+    buf = (char *) OSHash_Get(syscheck.fp, file_name);
+    if (buf != NULL) {
+        char c_sum[256 + 2];
 
         c_sum[0] = '\0';
         c_sum[255] = '\0';
 
+        /* If it returns < 0, we have already alerted */
+        if (c_read_file(file_name, buf, c_sum) < 0) {
+            return (0);
+        }
 
-         /* If it returns < 0, we will already have alerted. */
-         if(c_read_file(file_name, buf, c_sum) < 0)
-         {
-             return(0);
-         }
-
-
-         if(strcmp(c_sum, buf+6) != 0)
-         {
-             char alert_msg[OS_MAXSTR +1];
-             alert_msg[OS_MAXSTR] = '\0';
-             #ifdef WIN32
-             snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
-             #else
-             char *fullalert = NULL;
-             if(buf[5] == 's' || buf[5] == 'n')
-             {
-                 fullalert = seechanges_addfile(file_name);
-                 if(fullalert)
-                 {
+        if (strcmp(c_sum, buf + 6) != 0) {
+            char alert_msg[OS_MAXSTR + 1];
+
+            alert_msg[OS_MAXSTR] = '\0';
+
+            #ifdef WIN32
+            snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
+            #else
+            char *fullalert = NULL;
+
+            if (buf[5] == 's' || buf[5] == 'n') {
+                fullalert = seechanges_addfile(file_name);
+                if (fullalert) {
                     snprintf(alert_msg, OS_MAXSTR, "%s %s\n%s", c_sum, file_name, fullalert);
                     free(fullalert);
                     fullalert = NULL;
-                 }
-                 else
-                 {
-                     snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
-                 }
-             }
-             else
-             {
-                 snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
-             }
-             #endif
-             send_syscheck_msg(alert_msg);
-
-             return(1);
-         }
-
-         return(0);
-
-    }
+                } else {
+                    snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
+                }
+            } else {
+                snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
+            }
+            #endif
+            send_syscheck_msg(alert_msg);
 
-    return(0);
-}
+            return (1);
+        }
+        return (0);
+    } else {
+        /* New file */
+        char *c;
+        int i;
+        buf = strdup(file_name);
+
+        /* Find container directory */
+
+        while (c = strrchr(buf, '/'), c && c != buf) {
+            *c = '\0';
+
+            for (i = 0; syscheck.dir[i]; i++) {
+                if (strcmp(syscheck.dir[i], buf) == 0) {
+                    debug1("%s: DEBUG: Scanning new file '%s' with options for directory '%s'.", ARGV0, file_name, buf);
+                    read_dir(file_name, syscheck.opts[i], syscheck.filerestrict[i]);
+                    break;
+                }
+            }
 
+            if (syscheck.dir[i]) {
+                break;
+            }
+        }
 
+        free(buf);
+    }
 
+    return (0);
+}
 
-#ifdef USEINOTIFY
+#ifdef INOTIFY_ENABLED
 #include <sys/inotify.h>
 
-
 #define REALTIME_MONITOR_FLAGS  IN_MODIFY|IN_ATTRIB|IN_MOVED_FROM|IN_MOVED_TO|IN_CREATE|IN_DELETE|IN_DELETE_SELF
 #define REALTIME_EVENT_SIZE     (sizeof (struct inotify_event))
 #define REALTIME_EVENT_BUFFER   (2048 * (REALTIME_EVENT_SIZE + 16))
 
-
-
-/* Starts real time monitoring using inotify. */
+/* Start real time monitoring using inotify */
 int realtime_start()
 {
     verbose("%s: INFO: Initializing real time file monitoring (not started).", ARGV0);
 
-    syscheck.realtime = calloc(1, sizeof(rtfim));
-    if(syscheck.realtime == NULL)
-    {
-        ErrorExit(MEM_ERROR, ARGV0);
+    syscheck.realtime = (rtfim *) calloc(1, sizeof(rtfim));
+    if (syscheck.realtime == NULL) {
+        ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
     }
-    syscheck.realtime->dirtb = (void *)OSHash_Create();
+    syscheck.realtime->dirtb = OSHash_Create();
     syscheck.realtime->fd = -1;
 
-    #ifdef USEINOTIFY
+#ifdef INOTIFY_ENABLED
     syscheck.realtime->fd = inotify_init();
-    if(syscheck.realtime->fd < 0)
-    {
+    if (syscheck.realtime->fd < 0) {
         merror("%s: ERROR: Unable to initialize inotify.", ARGV0);
-        return(-1);
+        return (-1);
     }
-    #endif
+#endif
 
-    return(1);
+    return (1);
 }
 
-
-
-/* Adds a directory to real time checking. */
-int realtime_adddir(char *dir)
+/* Add a directory to real time checking */
+int realtime_adddir(const char *dir)
 {
-    if(!syscheck.realtime)
-    {
+    if (!syscheck.realtime) {
         realtime_start();
     }
 
-
-    /* Checking if it is ready to use. */
-    if(syscheck.realtime->fd < 0)
-    {
-        return(-1);
-    }
-    else
-    {
+    /* Check if it is ready to use */
+    if (syscheck.realtime->fd < 0) {
+        return (-1);
+    } else {
         int wd = 0;
 
+        if(syscheck.skip_nfs) {
+            short is_nfs = IsNFS(dir);
+            if( is_nfs == 1 ) {
+                merror("%s: ERROR: %s NFS Directories do not support iNotify.", ARGV0, dir);
+               return(-1);
+            }
+            else {
+                debug2("%s: DEBUG: syscheck.skip_nfs=%d, %s::is_nfs=%d", ARGV0, syscheck.skip_nfs, dir, is_nfs);
+            }
+        }
+
         wd = inotify_add_watch(syscheck.realtime->fd,
                                dir,
                                REALTIME_MONITOR_FLAGS);
-        if(wd < 0)
-        {
+        if (wd < 0) {
             merror("%s: ERROR: Unable to add directory to real time "
-                   "monitoring: '%s'. %d %d", ARGV0, dir, wd, errno);
-        }
-        else
-        {
-            char wdchar[32 +1];
+                   "monitoring: '%s'. %d %s", ARGV0, dir, wd, strerror(errno));
+        } else {
+            char wdchar[32 + 1];
             wdchar[32] = '\0';
             snprintf(wdchar, 32, "%d", wd);
 
-            /* Entry not present. */
-            if(!OSHash_Get(syscheck.realtime->dirtb, wdchar))
-            {
+            /* Entry not present */
+            if (!OSHash_Get(syscheck.realtime->dirtb, wdchar)) {
                 char *ndir;
 
                 ndir = strdup(dir);
-                if(ndir == NULL)
-                {
+                if (ndir == NULL) {
                     ErrorExit("%s: ERROR: Out of memory. Exiting.", ARGV0);
                 }
 
-                OSHash_Add(syscheck.realtime->dirtb, strdup(wdchar), ndir);
+                OSHash_Add(syscheck.realtime->dirtb, wdchar, ndir);
                 debug1("%s: DEBUG: Directory added for real time monitoring: "
                        "'%s'.", ARGV0, ndir);
             }
         }
     }
 
-    return(1);
+    return (1);
 }
 
-
-/* Process events in the real time queue. */
+/* Process events in the real time queue */
 int realtime_process()
 {
-    int len, i = 0;
-    char buf[REALTIME_EVENT_BUFFER +1];
+    ssize_t len;
+    size_t i = 0;
+    char buf[REALTIME_EVENT_BUFFER + 1];
     struct inotify_event *event;
 
     buf[REALTIME_EVENT_BUFFER] = '\0';
 
-
     len = read(syscheck.realtime->fd, buf, REALTIME_EVENT_BUFFER);
-    if (len < 0)
-    {
+    if (len < 0) {
         merror("%s: ERROR: Unable to read from real time buffer.", ARGV0);
-    }
-    else if (len > 0)
-    {
-        while (i < len)
-        {
-            event = (struct inotify_event *) &buf[i];
+    } else if (len > 0) {
+        buf[len] = '\0';
+        while (i < (size_t) len) {
+            event = (struct inotify_event *) (void *) &buf[i];
 
-            if(event->len)
-            {
-                char wdchar[32 +1];
-                char final_name[MAX_LINE +1];
+            if (event->len) {
+                char wdchar[32 + 1];
+                char final_name[MAX_LINE + 1];
 
                 wdchar[32] = '\0';
                 final_name[MAX_LINE] = '\0';
@@ -239,6 +226,11 @@ int realtime_process()
                 snprintf(final_name, MAX_LINE, "%s/%s",
                          (char *)OSHash_Get(syscheck.realtime->dirtb, wdchar),
                          event->name);
+               /* Need a sleep here to avoid triggering on vim edits
+                * (and finding the file removed)
+                */
+               sleep(1);
+
                 realtime_checksumfile(final_name);
             }
 
@@ -246,20 +238,17 @@ int realtime_process()
         }
     }
 
-    return(0);
+    return (0);
 }
 
-
-
-#elif WIN32
-typedef struct _win32rtfim
-{
+#elif defined(WIN32)
+typedef struct _win32rtfim {
     HANDLE h;
     OVERLAPPED overlap;
 
     char *dir;
-    TCHAR buffer[12288];
-}win32rtfim;
+    TCHAR buffer[1228800];
+} win32rtfim;
 
 int realtime_win32read(win32rtfim *rtlocald);
 
@@ -267,45 +256,39 @@ void CALLBACK RTCallBack(DWORD dwerror, DWORD dwBytes, LPOVERLAPPED overlap)
 {
     int lcount;
     size_t offset = 0;
-
     char *ptfile;
-    char wdchar[32 +1];
-    char final_path[MAX_LINE +1];
-
+    char wdchar[32 + 1];
+    char final_path[MAX_LINE + 1];
     win32rtfim *rtlocald;
-
     PFILE_NOTIFY_INFORMATION pinfo;
     TCHAR finalfile[MAX_PATH];
 
-    if(dwBytes == 0)
-    {
+    if (dwBytes == 0) {
         merror("%s: ERROR: real time call back called, but 0 bytes.", ARGV0);
+        rtlocald = OSHash_Get(syscheck.realtime->dirtb, "0");
+        if(rtlocald)
+            realtime_win32read(rtlocald);
+
         return;
     }
 
-    if(dwerror != ERROR_SUCCESS)
-    {
+    if (dwerror != ERROR_SUCCESS) {
         merror("%s: ERROR: real time call back called, but error is set.",
                ARGV0);
         return;
     }
 
-
-    /* Getting hash to parse the data. */
+    /* Get hash to parse the data */
     wdchar[32] = '\0';
     snprintf(wdchar, 32, "%d", (int)overlap->Offset);
     rtlocald = OSHash_Get(syscheck.realtime->dirtb, wdchar);
-    if(rtlocald == NULL)
-    {
+    if (rtlocald == NULL) {
         merror("%s: ERROR: real time call back called, but hash is empty.",
                ARGV0);
         return;
     }
 
-
-
-    do
-    {
+    do {
         pinfo = (PFILE_NOTIFY_INFORMATION) &rtlocald->buffer[offset];
         offset += pinfo->NextEntryOffset;
 
@@ -314,11 +297,9 @@ void CALLBACK RTCallBack(DWORD dwerror, DWORD dwBytes, LPOVERLAPPED overlap)
                                      finalfile, MAX_PATH - 1, NULL, NULL);
         finalfile[lcount] = TEXT('\0');
 
-
-        /* Change forward slashes to backslashes on finalfile. */
+        /* Change forward slashes to backslashes on finalfile */
         ptfile = strchr(finalfile, '\\');
-        while(ptfile)
-        {
+        while (ptfile) {
             *ptfile = '/';
             ptfile++;
 
@@ -328,31 +309,15 @@ void CALLBACK RTCallBack(DWORD dwerror, DWORD dwBytes, LPOVERLAPPED overlap)
         final_path[MAX_LINE] = '\0';
         snprintf(final_path, MAX_LINE, "%s/%s", rtlocald->dir, finalfile);
 
-
-        /* Checking the change. */
+        /* Check the change */
         realtime_checksumfile(final_path);
-
-
-        /*
-        if(pinfo->Action == FILE_ACTION_ADDED)
-        else if(pinfo->Action == FILE_ACTION_REMOVED)
-        else if(pinfo->Action == FILE_ACTION_MODIFIED)
-        else if(pinfo->Action == FILE_ACTION_RENAMED_OLD_NAME)
-        else if(pinfo->Action == FILE_ACTION_RENAMED_NEW_NAME)
-        else
-        */
-
-    }while(pinfo->NextEntryOffset != 0);
-
+    } while (pinfo->NextEntryOffset != 0);
 
     realtime_win32read(rtlocald);
 
-
     return;
 }
 
-
-
 int realtime_start()
 {
     verbose("%s: INFO: Initializing real time file monitoring (not started).", ARGV0);
@@ -361,7 +326,8 @@ int realtime_start()
     syscheck.realtime->dirtb = (void *)OSHash_Create();
     syscheck.realtime->fd = -1;
     syscheck.realtime->evt = CreateEvent(NULL, TRUE, FALSE, NULL);
-    return(0);
+
+    return (0);
 }
 
 int realtime_win32read(win32rtfim *rtlocald)
@@ -372,116 +338,98 @@ int realtime_win32read(win32rtfim *rtlocald)
                                rtlocald->buffer,
                                sizeof(rtlocald->buffer) / sizeof(TCHAR),
                                TRUE,
-                               FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE,
+                               FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SECURITY,
                                0,
                                &rtlocald->overlap,
                                RTCallBack);
-    if(rc == 0)
-    {
+    if (rc == 0) {
         merror("%s: ERROR: Unable to set directory for monitoring: %s",
                ARGV0, rtlocald->dir);
         sleep(2);
     }
 
-    return(0);
+    return (0);
 }
 
-int realtime_adddir(char *dir)
+int realtime_adddir(const char *dir)
 {
-    char wdchar[32 +1];
+    char wdchar[32 + 1];
     win32rtfim *rtlocald;
 
-
-    if(!syscheck.realtime)
-    {
+    if (!syscheck.realtime) {
         realtime_start();
     }
 
-
-    /* Maximum limit for realtime on Windows. */
-    if(syscheck.realtime->fd > 256)
-    {
+    /* Maximum limit for realtime on Windows */
+    if (syscheck.realtime->fd > 256) {
         merror("%s: ERROR: Unable to add directory to real time "
                "monitoring: '%s' - Maximum size permitted.", ARGV0, dir);
-        return(0);
+        return (0);
     }
 
-
     os_calloc(1, sizeof(win32rtfim), rtlocald);
 
-
     rtlocald->h = CreateFile(dir,
                              FILE_LIST_DIRECTORY,
-                             FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
+                             FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
                              NULL,
                              OPEN_EXISTING,
-                             FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED,
+                             FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
                              NULL);
 
 
-    if(rtlocald->h == INVALID_HANDLE_VALUE ||
-       rtlocald->h == NULL)
-    {
+    if (rtlocald->h == INVALID_HANDLE_VALUE ||
+            rtlocald->h == NULL) {
         free(rtlocald);
         rtlocald = NULL;
         merror("%s: ERROR: Unable to add directory to real time "
                "monitoring: '%s'.", ARGV0, dir);
-        return(0);
+        return (0);
     }
 
     rtlocald->overlap.Offset = ++syscheck.realtime->fd;
 
-
-
-    /* Setting key for hash. */
+    /* Set key for hash */
     wdchar[32] = '\0';
     snprintf(wdchar, 32, "%d", (int)rtlocald->overlap.Offset);
 
-
-    if(OSHash_Get(syscheck.realtime->dirtb, wdchar))
-    {
+    if (OSHash_Get(syscheck.realtime->dirtb, wdchar)) {
         merror("%s: ERROR: Entry already in the real time hash: %s",
                ARGV0, wdchar);
         CloseHandle(rtlocald->overlap.hEvent);
         free(rtlocald);
         rtlocald = NULL;
-        return(0);
+        return (0);
     }
 
-
-    /* Adding final elements to the hash. */
+    /* Add final elements to the hash */
     os_strdup(dir, rtlocald->dir);
-
     OSHash_Add(syscheck.realtime->dirtb, strdup(wdchar), rtlocald);
 
-
-    /* Adding directory to be monitored. */
+    /* Add directory to be monitored */
     realtime_win32read(rtlocald);
 
-
-    return(1);
+    return (1);
 }
 
+#else /* !WIN32 */
 
-
-
-
-#else
 int realtime_start()
 {
-    verbose("%s: ERROR: Unable to initalize real time file monitoring.", ARGV0);
-    return(0);
+    verbose("%s: ERROR: Unable to initialize real time file monitoring.", ARGV0);
+
+    return (0);
 }
 
-int realtime_adddir(char *dir)
+int realtime_adddir(__attribute__((unused)) const char *dir)
 {
-    return(0);
+    return (0);
 }
 
 int realtime_process()
 {
-    return(0);
+    return (0);
 }
 
-#endif
-/* EOF */
+#endif /* WIN32 */
+