X-Git-Url: http://ftp.carnet.hr/carnet-debian/scm?p=ossec-hids.git;a=blobdiff_plain;f=src%2Fsyscheckd%2Fseechanges.c;fp=src%2Fsyscheckd%2Fseechanges.c;h=39ee33fb21cbf7d845020f6b36d4592d818da02a;hp=0000000000000000000000000000000000000000;hb=301048b51990573e58a30dc4a5bb4ec285cad554;hpb=914feba5d54f979cd5d7e69c349c3d01f630042a diff --git a/src/syscheckd/seechanges.c b/src/syscheckd/seechanges.c new file mode 100755 index 0000000..39ee33f --- /dev/null +++ b/src/syscheckd/seechanges.c @@ -0,0 +1,271 @@ +/* @(#) $Id$ */ + +/* Copyright (C) 2009 Trend Micro Inc. + * All rights reserved. + * + * This program is a free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public + * License (version 2) as published by the FSF - Free Software + * Foundation + */ + + + +#include "shared.h" +#include "os_crypto/md5/md5_op.h" + + + +/* Generate diffs alerts. */ +char *gen_diff_alert(char *filename, int alert_diff_time) +{ + int n = 0; + FILE *fp; + char *tmp_str; + 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); + + fp = fopen(buf, "r"); + if(!fp) + { + merror("%s: ERROR: Unable to generate diff alert.", ARGV0); + return(NULL); + } + + 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. */ + buf[n] = '\0'; + tmp_str = strrchr(buf, '\n'); + if(tmp_str) + *tmp_str = '\0'; + else + { + /* Weird diff with only one large line. */ + buf[256] = '\0'; + } + } + else + { + buf[n] = '\0'; + } + + n = 0; + + + /* 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; + else if(n >= 19) + { + *tmp_str = '\0'; + break; + } + n++; + tmp_str++; + } + + + /* Creating alert. */ + snprintf(diff_alert, 4096 -1, "%s%s", + buf, n>=19? + "\nMore changes..": + ""); + + + fclose(fp); + return(strdup(diff_alert)); +} + + +int seechanges_dupfile(char *old, char *new) +{ + int n; + FILE *fpr; + FILE *fpw; + unsigned char buf[2048 +1]; + + buf[2048] = '\0'; + + fpr = fopen(old,"r"); + fpw = fopen(new,"w"); + + if(!fpr || !fpw) + { + return(0); + } + + while((n = fread(buf, 1, 2048, fpr)) > 0) + { + buf[n] = '\0'; + fwrite(buf, n, 1, fpw); + + } + + fclose(fpr); + fclose(fpw); + return(1); +} + + +int seechanges_createpath(char *filename) +{ + char *buffer = NULL; + char *tmpstr = NULL; + char *newdir = NULL; + + + os_strdup(filename, buffer); + newdir = buffer; + tmpstr = strchr(buffer +1, '/'); + if(!tmpstr) + { + merror("%s: ERROR: Invalid path name: '%s'", ARGV0, filename); + free(buffer); + return(0); + } + *tmpstr = '\0'; + tmpstr++; + + + while(1) + { + if(IsDir(newdir) != 0) + { + #ifndef WIN32 + if(mkdir(newdir, 0770) == -1) + #else + if(mkdir(newdir) == -1) + #endif + { + merror(MKDIR_ERROR, ARGV0, newdir); + free(buffer); + return(0); + } + } + + if(*tmpstr == '\0') + { + break; + } + + tmpstr[-1] = '/'; + tmpstr = strchr(tmpstr, '/'); + if(!tmpstr) + { + break; + } + *tmpstr = '\0'; + tmpstr++; + } + + free(buffer); + return(1); +} + + +/* Checks if the file has changed */ +char *seechanges_addfile(char *filename) +{ + int date_of_change; + char old_location[OS_MAXSTR +1]; + char tmp_location[OS_MAXSTR +1]; + char diff_cmd[OS_MAXSTR +1]; + + os_md5 md5sum_old; + os_md5 md5sum_new; + + old_location[OS_MAXSTR] = '\0'; + tmp_location[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) + { + seechanges_createpath(old_location); + if(seechanges_dupfile(filename, old_location) != 1) + { + merror(RENAME_ERROR, ARGV0, filename); + } + 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); + } + + + /* If they match, keep the old file and remove the new. */ + if(strcmp(md5sum_new, md5sum_old) == 0) + { + return(NULL); + } + + + /* 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); + 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); + } + + + /* Generate alert. */ + return(gen_diff_alert(filename, date_of_change)); + + + return(NULL); +} + + + +/* EOF */