X-Git-Url: http://ftp.carnet.hr/carnet-debian/scm?a=blobdiff_plain;f=src%2Fsyscheckd%2Fseechanges.c;h=7cf82215ebb1415345bbd93ef8289cbf04db8b89;hb=HEAD;hp=39ee33fb21cbf7d845020f6b36d4592d818da02a;hpb=301048b51990573e58a30dc4a5bb4ec285cad554;p=ossec-hids.git diff --git a/src/syscheckd/seechanges.c b/src/syscheckd/seechanges.c old mode 100755 new mode 100644 index 39ee33f..7cf8221 --- a/src/syscheckd/seechanges.c +++ b/src/syscheckd/seechanges.c @@ -1,5 +1,3 @@ -/* @(#) $Id$ */ - /* Copyright (C) 2009 Trend Micro Inc. * All rights reserved. * @@ -9,169 +7,209 @@ * 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 +/* Global variables */ +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 + +/* 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. */ -char *gen_diff_alert(char *filename, int alert_diff_time) +/* 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. */ - buf[256] = '\0'; + } 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) - break; - else if(n >= 19) - { - *tmp_str = '\0'; + if (!tmp_str) { + break; + } else if (n >= 19) { + *tmp_str = '\0'; break; } n++; - tmp_str++; + 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); } - 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); + 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'; @@ -179,93 +217,203 @@ 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) { - int date_of_change; - char old_location[OS_MAXSTR +1]; - char tmp_location[OS_MAXSTR +1]; - char diff_cmd[OS_MAXSTR +1]; - + 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); - - - /* If the file is not there, rename new location to last location. */ - if(OS_MD5_File(old_location, md5sum_old) != 0) - { + 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 */ + 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. */ - 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); - rename(old_location, tmp_location); + old_date_of_change = File_DateofChange(old_location); + + snprintf( + tmp_location, + sizeof(tmp_location), + "%s/local/%s/state.%d", + DIFF_DIR_PATH, + filename + 1, + (int)old_date_of_change + ); + + + 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); + } - /* 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); + 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; + } - /* Generate alert. */ - return(gen_diff_alert(filename, date_of_change)); + if (symlink(diff_location, diff_tmp) == -1) { + merror(LINK_ERROR, ARGV0, diff_location, diff_tmp, errno, strerror(errno)); + goto cleanup; + } + if (is_nodiff((filename))) { + /* Dont leak sensible data with a diff hanging around */ + FILE *fdiff; + char* nodiff_message = ""; + 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; + } - return(NULL); -} + /* Success */ + status = 0; + }; +cleanup: + unlink(old_tmp); + unlink(new_tmp); + unlink(diff_tmp); + if (status == -1) + return (NULL); -/* EOF */ + /* Generate alert */ + return (gen_diff_alert(filename, new_date_of_change)); +}