new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / syscheckd / seechanges.c
old mode 100755 (executable)
new mode 100644 (file)
index 7bf2ee1..7cf8221
@@ -1,6 +1,3 @@
-/* @(#) $Id: ./src/syscheckd/seechanges.c, 2011/09/08 dcid Exp $
- */
-
 /* Copyright (C) 2009 Trend Micro Inc.
  * All rights reserved.
  *
  * Foundation
  */
 
-
-
 #include "shared.h"
 #include "os_crypto/md5/md5_op.h"
+#include "syscheck.h"
+
+/* Prototypes */
+static char *gen_diff_alert(const char *filename, time_t alert_diff_time) __attribute__((nonnull));
+static int seechanges_dupfile(const char *old, const char *current) __attribute__((nonnull));
+static int seechanges_createpath(const char *filename) __attribute__((nonnull));
 
 #ifdef USE_MAGIC
 #include <magic.h>
+
+/* Global variables */
 extern magic_t magic_cookie;
 
-int is_text(magic_t cookie, const void* buf, size_t len)
+
+int is_text(magic_t cookie, const void *buf, size_t len)
 {
-    const char* magic = magic_buffer(cookie, buf, len);
+    const char *magic = magic_buffer(cookie, buf, len);
 
-    if(!magic)
-    {
-        const char* err = magic_error(cookie);
+    if (!magic) {
+        const char *err = magic_error(cookie);
         merror("%s: ERROR: magic_buffer: %s", ARGV0, err ? err : "unknown");
-        return(1); // TODO default to true?
-    }
-    else
-    {
-        if(strncmp(magic, "text/", 5) == 0) return(1);
+        return (1); // TODO default to true?
+    } else {
+        if (strncmp(magic, "text/", 5) == 0) {
+            return (1);
+        }
     }
 
-    return(0);
+    return (0);
 }
 #endif
 
-/* Generate diffs alerts. */
-char *gen_diff_alert(char *filename, int alert_diff_time)
+/* Return TRUE if the file name match one of the ``nodiff`` entries.
+   Return FALSE otherwise */
+int is_nodiff(const char *filename){
+    if (syscheck.nodiff){
+        int i;
+        for (i = 0; syscheck.nodiff[i] != NULL; i++){
+            if (strncasecmp(syscheck.nodiff[i], filename,
+                            strlen(syscheck.nodiff[i])) == 0) {
+                return (TRUE);
+            }
+        }
+    }
+    if (syscheck.nodiff_regex) {
+        int i;
+        for (i = 0; syscheck.nodiff_regex[i] != NULL; i++) {
+            if (OSMatch_Execute(filename, strlen(filename),
+                                syscheck.nodiff_regex[i])) {
+                 return (TRUE);
+            }
+        }
+    }
+    return (FALSE);
+}
+
+/* Generate diffs alerts */
+static char *gen_diff_alert(const char *filename, time_t alert_diff_time)
 {
-    int n = 0;
+    size_t n = 0;
     FILE *fp;
     char *tmp_str;
-    char buf[OS_MAXSTR +1];
-    char diff_alert[OS_MAXSTR +1];
+    char buf[OS_MAXSTR + 1];
+    char diff_alert[OS_MAXSTR + 1];
 
     buf[OS_MAXSTR] = '\0';
     diff_alert[OS_MAXSTR] = '\0';
 
     snprintf(buf, OS_MAXSTR, "%s/local/%s/diff.%d",
-             DIFF_DIR_PATH, filename,  alert_diff_time);
+             DIFF_DIR_PATH, filename,  (int)alert_diff_time);
 
     fp = fopen(buf, "r");
-    if(!fp)
-    {
+    if (!fp) {
         merror("%s: ERROR: Unable to generate diff alert.", ARGV0);
-        return(NULL);
+        return (NULL);
     }
 
-    n = fread(buf, 1, 4096 -1, fp);
-    if(n <= 0)
-    {
+    n = fread(buf, 1, 4096 - 1, fp);
+    if (n <= 0) {
         merror("%s: ERROR: Unable to generate diff alert (fread).", ARGV0);
         fclose(fp);
-        return(NULL);
-    }
-    else if(n >= 4000)
-    {
-        /* We need to clear the last new line. */
+        return (NULL);
+    } else if (n >= 4000) {
+        /* Clear the last newline */
         buf[n] = '\0';
         tmp_str = strrchr(buf, '\n');
-        if(tmp_str)
+        if (tmp_str) {
             *tmp_str = '\0';
-        else
-        {
-            /* Weird diff with only one large line. */
+        } else {
+            /* Weird diff with only one large line */
             buf[256] = '\0';
         }
-    }
-    else
-    {
+    } else {
         buf[n] = '\0';
     }
 
     n = 0;
 
-
-    /* Getting up to 20 line changes. */
+    /* Get up to 20 line changes */
     tmp_str = buf;
 
-
-    while(tmp_str && (*tmp_str != '\0'))
-    {
+    while (tmp_str && (*tmp_str != '\0')) {
         tmp_str = strchr(tmp_str, '\n');
-        if(!tmp_str)
+        if (!tmp_str) {
             break;
-        else if(n >= 19)
-        {
+        } else if (n >= 19) {
             *tmp_str = '\0';
             break;
         }
@@ -106,105 +122,94 @@ char *gen_diff_alert(char *filename, int alert_diff_time)
         tmp_str++;
     }
 
-
-    /* Creating alert. */
-    snprintf(diff_alert, 4096 -1, "%s%s",
-             buf, n>=19?
-             "\nMore changes..":
+    /* Create alert */
+    snprintf(diff_alert, 4096 - 1, "%s%s",
+             buf, n >= 19 ?
+             "\nMore changes.." :
              "");
 
-
     fclose(fp);
-    return(strdup(diff_alert));
+    return (strdup(diff_alert));
 }
 
-
-int seechanges_dupfile(char *old, char *new)
+static int seechanges_dupfile(const char *old, const char *current)
 {
-    int n;
+    size_t n;
     FILE *fpr;
     FILE *fpw;
-    unsigned char buf[2048 +1];
+    unsigned char buf[2048 + 1];
 
     buf[2048] = '\0';
 
-    fpr = fopen(old,"r");
-    fpw = fopen(new,"w");
+    fpr = fopen(old, "r");
+    if (!fpr) {
+        return (0);
+    }
 
-    if(!fpr || !fpw)
-    {
-        return(0);
+    fpw = fopen(current, "w");
+    if (!fpw) {
+        fclose(fpr);
+        return (0);
     }
 
     n = fread(buf, 1, 2048, fpr);
-    #ifdef USE_MAGIC
-    if(is_text(magic_cookie, buf, n) == 0)
-    {
+#ifdef USE_MAGIC
+    if (is_text(magic_cookie, buf, n) == 0) {
         goto cleanup;
     }
-    #endif
+#endif
 
-    do
-    {
+    do {
         buf[n] = '\0';
         fwrite(buf, n, 1, fpw);
-    }
-    while((n = fread(buf, 1, 2048, fpr)) > 0);
+    } while ((n = fread(buf, 1, 2048, fpr)) > 0);
 
 #ifdef USE_MAGIC
 cleanup:
 #endif
     fclose(fpr);
     fclose(fpw);
-    return(1);
+    return (1);
 }
 
-
-int seechanges_createpath(char *filename)
+static int seechanges_createpath(const char *filename)
 {
     char *buffer = NULL;
     char *tmpstr = NULL;
     char *newdir = NULL;
 
-
     os_strdup(filename, buffer);
     newdir = buffer;
-    tmpstr = strchr(buffer +1, '/');
-    if(!tmpstr)
-    {
+    tmpstr = strchr(buffer + 1, '/');
+    if (!tmpstr) {
         merror("%s: ERROR: Invalid path name: '%s'", ARGV0, filename);
         free(buffer);
-        return(0);
+        return (0);
     }
     *tmpstr = '\0';
     tmpstr++;
 
-
-    while(1)
-    {
-        if(IsDir(newdir) != 0)
-        {
-            #ifndef WIN32
-            if(mkdir(newdir, 0770) == -1)
-            #else
-            if(mkdir(newdir) == -1)
-            #endif
+    while (1) {
+        if (IsDir(newdir) != 0) {
+#ifndef WIN32
+            if (mkdir(newdir, 0770) == -1)
+#else
+            if (mkdir(newdir) == -1)
+#endif
             {
-                merror(MKDIR_ERROR, ARGV0, newdir);
+                merror(MKDIR_ERROR, ARGV0, newdir, errno, strerror(errno));
                 free(buffer);
-                return(0);
+                return (0);
             }
         }
 
-        if(*tmpstr == '\0')
-        {
+        if (*tmpstr == '\0') {
             break;
         }
 
         tmpstr[-1] = '/';
         tmpstr = strchr(tmpstr, '/');
-        if(!tmpstr)
-        {
+        if (!tmpstr) {
             break;
         }
         *tmpstr = '\0';
@@ -212,30 +217,25 @@ int seechanges_createpath(char *filename)
     }
 
     free(buffer);
-    return(1);
+    return (1);
 }
 
-
-/* Checks if the file has changed */
-char *seechanges_addfile(char *filename)
+/* Check if the file has changed */
+char *seechanges_addfile(const char *filename)
 {
     time_t old_date_of_change;
     time_t new_date_of_change;
-
-    char old_location[OS_MAXSTR +1];
-    char tmp_location[OS_MAXSTR +1];
+    char old_location[OS_MAXSTR + 1];
+    char tmp_location[OS_MAXSTR + 1];
     char diff_location[OS_MAXSTR + 1];
     char old_tmp[OS_MAXSTR + 1];
     char new_tmp[OS_MAXSTR + 1];
     char diff_tmp[OS_MAXSTR + 1];
-
-    char diff_cmd[OS_MAXSTR +1];
-
+    char diff_cmd[OS_MAXSTR + 1];
     os_md5 md5sum_old;
     os_md5 md5sum_new;
     int status = -1;
 
-
     old_location[OS_MAXSTR] = '\0';
     tmp_location[OS_MAXSTR] = '\0';
     diff_location[OS_MAXSTR] = '\0';
@@ -246,7 +246,6 @@ char *seechanges_addfile(char *filename)
     md5sum_new[0] = '\0';
     md5sum_old[0] = '\0';
 
-
     snprintf(
         old_location,
         OS_MAXSTR,
@@ -256,41 +255,43 @@ char *seechanges_addfile(char *filename)
         DIFF_LAST_FILE
     );
 
-
-    /* If the file is not there, rename new location to last location. */
-    if(OS_MD5_File(old_location, md5sum_old) != 0)
-    {
+    /* If the file is not there, rename new location to last location */
+    if (OS_MD5_File(old_location, md5sum_old, OS_BINARY) != 0) {
         seechanges_createpath(old_location);
-        if(seechanges_dupfile(filename, old_location) != 1)
-        {
-            merror(RENAME_ERROR, ARGV0, filename);
+        if (seechanges_dupfile(filename, old_location) != 1) {
+            merror(RENAME_ERROR, ARGV0, filename, old_location, errno, strerror(errno));
         }
-        return(NULL);
+        return (NULL);
     }
 
-
-    /* Get md5sum of the new file. */
-    if(OS_MD5_File(filename, md5sum_new) != 0)
-    {
-        //merror("%s: ERROR: Invalid internal state (missing '%s').",
-        //       ARGV0, filename);
-        return(NULL);
+    /* Get md5sum of the new file */
+    if (OS_MD5_File(filename, md5sum_new, OS_BINARY) != 0) {
+        return (NULL);
     }
 
-
-    /* If they match, keep the old file and remove the new. */
-    if(strcmp(md5sum_new, md5sum_old) == 0)
-    {
-        return(NULL);
+    /* If they match, keep the old file and remove the new */
+    if (strcmp(md5sum_new, md5sum_old) == 0) {
+        return (NULL);
     }
 
+    /* Save the old file at timestamp and rename new to last */
+    old_date_of_change = File_DateofChange(old_location);
+
+    snprintf(
+        tmp_location,
+        OS_MAXSTR,
+        "%s/local/%s/state.%d",
+        DIFF_DIR_PATH,
+        filename + 1,
+        (int)old_date_of_change
+    );
 
     /* Saving the old file at timestamp and renaming new to last. */
     old_date_of_change = File_DateofChange(old_location);
 
     snprintf(
         tmp_location,
-        OS_MAXSTR,
+        sizeof(tmp_location),
         "%s/local/%s/state.%d",
         DIFF_DIR_PATH,
         filename + 1,
@@ -298,13 +299,19 @@ char *seechanges_addfile(char *filename)
     );
 
 
-    rename(old_location, tmp_location);
+    if((rename(old_location, tmp_location)) < 0) {
+        merror("%s: ERROR rename of %s failed: %s", ARGV0, old_location, strerror(errno));
+    }
     if(seechanges_dupfile(filename, old_location) != 1)
     {
         merror("%s: ERROR: Unable to create snapshot for %s",ARGV0, filename);
         return(NULL);
     }
 
+    if (seechanges_dupfile(filename, old_location) != 1) {
+        merror("%s: ERROR: Unable to create snapshot for %s", ARGV0, filename);
+        return (NULL);
+    }
 
     new_date_of_change = File_DateofChange(old_location);
 
@@ -340,7 +347,6 @@ char *seechanges_addfile(char *filename)
         md5sum_new,
         (int)new_date_of_change
     );
-
     /* Create diff location */
     snprintf(
         diff_location,
@@ -367,28 +373,38 @@ char *seechanges_addfile(char *filename)
         goto cleanup;
     }
 
+    if (is_nodiff((filename))) {
+        /* Dont leak sensible data with a diff hanging around */
+        FILE *fdiff;
+        char* nodiff_message = "<Diff truncated because nodiff option>";
+        fdiff = fopen(diff_location, "w");
+        if (!fdiff){
+            merror("%s: ERROR: Unable to open file for writing `%s`", ARGV0, diff_location);
+            goto cleanup;
+        }
+        fwrite(nodiff_message, strlen(nodiff_message) + 1, 1, fdiff);
+        fclose(fdiff);
+        /* Success */
+        status = 0;
+    } else {
+        /* OK, run diff */
+        snprintf(
+            diff_cmd,
+            2048,
+            "diff \"%s\" \"%s\" > \"%s\" 2> /dev/null",
+            new_tmp,
+            old_tmp,
+            diff_tmp
+        );
+
+        if (system(diff_cmd) != 256) {
+            merror("%s: ERROR: Unable to run `%s`", ARGV0, diff_cmd);
+            goto cleanup;
+        }
 
-
-    /* Run diff. */
-    snprintf(
-        diff_cmd,
-        2048,
-        "diff \"%s\" \"%s\" > \"%s\" 2> /dev/null",
-        new_tmp,
-        old_tmp,
-        diff_tmp
-    );
-
-
-
-    if(system(diff_cmd) != 256) {
-        merror("%s: ERROR: Unable to run diff for %s", ARGV0, filename);
-        goto cleanup;
-
-    }
-
-    /* Success */
-    status = 0;
+        /* Success */
+        status = 0;
+    };
 
 cleanup:
     unlink(old_tmp);
@@ -398,10 +414,6 @@ cleanup:
     if (status == -1)
         return (NULL);
 
-    /* Generate alert. */
+    /* Generate alert */
     return (gen_diff_alert(filename, new_date_of_change));
 }
-
-
-
-/* EOF */