dodan override za lintian
[ossec-hids.git] / src / syscheckd / seechanges.c
index 39ee33f..7bf2ee1 100755 (executable)
@@ -1,4 +1,5 @@
-/* @(#) $Id$ */
+/* @(#) $Id: ./src/syscheckd/seechanges.c, 2011/09/08 dcid Exp $
+ */
 
 /* Copyright (C) 2009 Trend Micro Inc.
  * All rights reserved.
 #include "shared.h"
 #include "os_crypto/md5/md5_op.h"
 
+#ifdef USE_MAGIC
+#include <magic.h>
+extern magic_t magic_cookie;
 
+int is_text(magic_t cookie, const void* buf, size_t len)
+{
+    const char* magic = magic_buffer(cookie, buf, len);
+
+    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(0);
+}
+#endif
 
 /* Generate diffs alerts. */
 char *gen_diff_alert(char *filename, int alert_diff_time)
@@ -30,7 +52,7 @@ char *gen_diff_alert(char *filename, int alert_diff_time)
 
     snprintf(buf, OS_MAXSTR, "%s/local/%s/diff.%d",
              DIFF_DIR_PATH, filename,  alert_diff_time);
-    
+
     fp = fopen(buf, "r");
     if(!fp)
     {
@@ -55,7 +77,7 @@ char *gen_diff_alert(char *filename, int alert_diff_time)
         else
         {
             /* Weird diff with only one large line. */
-            buf[256] = '\0';    
+            buf[256] = '\0';
         }
     }
     else
@@ -69,19 +91,19 @@ char *gen_diff_alert(char *filename, int alert_diff_time)
     /* Getting up to 20 line changes. */
     tmp_str = buf;
 
-    
+
     while(tmp_str && (*tmp_str != '\0'))
     {
         tmp_str = strchr(tmp_str, '\n');
         if(!tmp_str)
-            break;    
+            break;
         else if(n >= 19)
         {
-            *tmp_str = '\0';    
+            *tmp_str = '\0';
             break;
         }
         n++;
-        tmp_str++;    
+        tmp_str++;
     }
 
 
@@ -90,8 +112,8 @@ char *gen_diff_alert(char *filename, int alert_diff_time)
              buf, n>=19?
              "\nMore changes..":
              "");
-    
-    
+
+
     fclose(fp);
     return(strdup(diff_alert));
 }
@@ -114,13 +136,24 @@ int seechanges_dupfile(char *old, char *new)
         return(0);
     }
 
-    while((n = fread(buf, 1, 2048, fpr)) > 0)
+    n = fread(buf, 1, 2048, fpr);
+    #ifdef USE_MAGIC
+    if(is_text(magic_cookie, buf, n) == 0)
+    {
+        goto cleanup;
+    }
+    #endif
+
+    do
     {
         buf[n] = '\0';
         fwrite(buf, n, 1, fpw);
-
     }
+    while((n = fread(buf, 1, 2048, fpr)) > 0);
 
+#ifdef USE_MAGIC
+cleanup:
+#endif
     fclose(fpr);
     fclose(fpw);
     return(1);
@@ -133,7 +166,7 @@ int seechanges_createpath(char *filename)
     char *tmpstr = NULL;
     char *newdir = NULL;
 
-    
+
     os_strdup(filename, buffer);
     newdir = buffer;
     tmpstr = strchr(buffer +1, '/');
@@ -153,9 +186,9 @@ int seechanges_createpath(char *filename)
         {
             #ifndef WIN32
             if(mkdir(newdir, 0770) == -1)
-            #else    
+            #else
             if(mkdir(newdir) == -1)
-            #endif    
+            #endif
             {
                 merror(MKDIR_ERROR, ARGV0, newdir);
                 free(buffer);
@@ -186,23 +219,42 @@ int seechanges_createpath(char *filename)
 /* Checks if the file has changed */
 char *seechanges_addfile(char *filename)
 {
-    int date_of_change;
+    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 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];
 
     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';
+    old_tmp[OS_MAXSTR] = '\0';
+    new_tmp[OS_MAXSTR] = '\0';
+    diff_tmp[OS_MAXSTR] = '\0';
     diff_cmd[OS_MAXSTR] = '\0';
     md5sum_new[0] = '\0';
     md5sum_old[0] = '\0';
 
 
-    snprintf(old_location, OS_MAXSTR, "%s/local/%s/%s", DIFF_DIR_PATH, filename +1,
-             DIFF_LAST_FILE);
+    snprintf(
+        old_location,
+        OS_MAXSTR,
+        "%s/local/%s/%s",
+        DIFF_DIR_PATH,
+        filename + 1,
+        DIFF_LAST_FILE
+    );
 
 
     /* If the file is not there, rename new location to last location. */
@@ -221,7 +273,7 @@ char *seechanges_addfile(char *filename)
     if(OS_MD5_File(filename, md5sum_new) != 0)
     {
         //merror("%s: ERROR: Invalid internal state (missing '%s').",
-        //       ARGV0, filename); 
+        //       ARGV0, filename);
         return(NULL);
     }
 
@@ -234,9 +286,18 @@ char *seechanges_addfile(char *filename)
 
 
     /* Saving the old file at timestamp and renaming new to last. */
-    date_of_change = File_DateofChange(old_location);
-    snprintf(tmp_location, OS_MAXSTR, "%s/local/%s/state.%d", DIFF_DIR_PATH, filename +1,
-             date_of_change);
+    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
+    );
+
+
     rename(old_location, tmp_location);
     if(seechanges_dupfile(filename, old_location) != 1)
     {
@@ -245,25 +306,100 @@ char *seechanges_addfile(char *filename)
     }
 
 
+    new_date_of_change = File_DateofChange(old_location);
+
+    /* Create file names */
+    snprintf(
+        old_tmp,
+        OS_MAXSTR,
+        "%s/%s/syscheck-changes-%s-%d",
+        DEFAULTDIR,
+        TMP_DIR,
+        md5sum_old,
+        (int)old_date_of_change
+    );
+
+    snprintf(
+        new_tmp,
+        OS_MAXSTR,
+        "%s/%s/syscheck-changes-%s-%d",
+        DEFAULTDIR,
+        TMP_DIR,
+        md5sum_new,
+        (int)new_date_of_change
+    );
+
+    snprintf(
+        diff_tmp,
+        OS_MAXSTR,
+        "%s/%s/syscheck-changes-%s-%d-%s-%d",
+        DEFAULTDIR,
+        TMP_DIR,
+        md5sum_old,
+        (int)old_date_of_change,
+        md5sum_new,
+        (int)new_date_of_change
+    );
+
+    /* Create diff location */
+    snprintf(
+        diff_location,
+        OS_MAXSTR,
+        "%s/local/%s/diff.%d",
+        DIFF_DIR_PATH,
+        filename + 1,
+        (int)new_date_of_change
+    );
+
+    /* Create symlinks */
+    if (symlink(old_location, old_tmp) == -1) {
+        merror(LINK_ERROR, ARGV0, old_location, old_tmp, errno, strerror(errno));
+        goto cleanup;
+    }
+
+    if (symlink(tmp_location, new_tmp) == -1) {
+        merror(LINK_ERROR, ARGV0, tmp_location, new_tmp, errno, strerror(errno));
+        goto cleanup;
+    }
+
+    if (symlink(diff_location, diff_tmp) == -1) {
+        merror(LINK_ERROR, ARGV0, diff_location, diff_tmp, errno, strerror(errno));
+        goto cleanup;
+    }
+
+
+
     /* Run diff. */
-    date_of_change = File_DateofChange(old_location);
-    snprintf(diff_cmd, 2048, "diff \"%s\" \"%s\" > \"%s/local/%s/diff.%d\" " 
-             "2>/dev/null",
-             tmp_location, old_location, 
-             DIFF_DIR_PATH, filename +1, date_of_change);
-    if(system(diff_cmd) != 256)
-    {
-        merror("%s: ERROR: Unable to run diff for %s",
-               ARGV0,  filename);
-        return(NULL); 
+    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;
 
-    /* Generate alert. */
-    return(gen_diff_alert(filename, date_of_change));
+cleanup:
+    unlink(old_tmp);
+    unlink(new_tmp);
+    unlink(diff_tmp);
 
+    if (status == -1)
+        return (NULL);
 
-    return(NULL);
+    /* Generate alert. */
+    return (gen_diff_alert(filename, new_date_of_change));
 }