1 /* Copyright (C) 2009 Trend Micro Inc.
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
11 #include "os_crypto/md5/md5_op.h"
15 static char *gen_diff_alert(const char *filename, time_t alert_diff_time) __attribute__((nonnull));
16 static int seechanges_dupfile(const char *old, const char *current) __attribute__((nonnull));
17 static int seechanges_createpath(const char *filename) __attribute__((nonnull));
22 /* Global variables */
23 extern magic_t magic_cookie;
26 int is_text(magic_t cookie, const void *buf, size_t len)
28 const char *magic = magic_buffer(cookie, buf, len);
31 const char *err = magic_error(cookie);
32 merror("%s: ERROR: magic_buffer: %s", ARGV0, err ? err : "unknown");
33 return (1); // TODO default to true?
35 if (strncmp(magic, "text/", 5) == 0) {
44 /* Return TRUE if the file name match one of the ``nodiff`` entries.
45 Return FALSE otherwise */
46 int is_nodiff(const char *filename){
49 for (i = 0; syscheck.nodiff[i] != NULL; i++){
50 if (strncasecmp(syscheck.nodiff[i], filename,
51 strlen(syscheck.nodiff[i])) == 0) {
56 if (syscheck.nodiff_regex) {
58 for (i = 0; syscheck.nodiff_regex[i] != NULL; i++) {
59 if (OSMatch_Execute(filename, strlen(filename),
60 syscheck.nodiff_regex[i])) {
68 /* Generate diffs alerts */
69 static char *gen_diff_alert(const char *filename, time_t alert_diff_time)
74 char buf[OS_MAXSTR + 1];
75 char diff_alert[OS_MAXSTR + 1];
77 buf[OS_MAXSTR] = '\0';
78 diff_alert[OS_MAXSTR] = '\0';
80 snprintf(buf, OS_MAXSTR, "%s/local/%s/diff.%d",
81 DIFF_DIR_PATH, filename, (int)alert_diff_time);
85 merror("%s: ERROR: Unable to generate diff alert.", ARGV0);
89 n = fread(buf, 1, 4096 - 1, fp);
91 merror("%s: ERROR: Unable to generate diff alert (fread).", ARGV0);
94 } else if (n >= 4000) {
95 /* Clear the last newline */
97 tmp_str = strrchr(buf, '\n');
101 /* Weird diff with only one large line */
110 /* Get up to 20 line changes */
113 while (tmp_str && (*tmp_str != '\0')) {
114 tmp_str = strchr(tmp_str, '\n');
117 } else if (n >= 19) {
126 snprintf(diff_alert, 4096 - 1, "%s%s",
132 return (strdup(diff_alert));
135 static int seechanges_dupfile(const char *old, const char *current)
140 unsigned char buf[2048 + 1];
144 fpr = fopen(old, "r");
149 fpw = fopen(current, "w");
155 n = fread(buf, 1, 2048, fpr);
157 if (is_text(magic_cookie, buf, n) == 0) {
164 fwrite(buf, n, 1, fpw);
165 } while ((n = fread(buf, 1, 2048, fpr)) > 0);
175 static int seechanges_createpath(const char *filename)
181 os_strdup(filename, buffer);
183 tmpstr = strchr(buffer + 1, '/');
185 merror("%s: ERROR: Invalid path name: '%s'", ARGV0, filename);
193 if (IsDir(newdir) != 0) {
195 if (mkdir(newdir, 0770) == -1)
197 if (mkdir(newdir) == -1)
200 merror(MKDIR_ERROR, ARGV0, newdir, errno, strerror(errno));
206 if (*tmpstr == '\0') {
211 tmpstr = strchr(tmpstr, '/');
223 /* Check if the file has changed */
224 char *seechanges_addfile(const char *filename)
226 time_t old_date_of_change;
227 time_t new_date_of_change;
228 char old_location[OS_MAXSTR + 1];
229 char tmp_location[OS_MAXSTR + 1];
230 char diff_location[OS_MAXSTR + 1];
231 char old_tmp[OS_MAXSTR + 1];
232 char new_tmp[OS_MAXSTR + 1];
233 char diff_tmp[OS_MAXSTR + 1];
234 char diff_cmd[OS_MAXSTR + 1];
239 old_location[OS_MAXSTR] = '\0';
240 tmp_location[OS_MAXSTR] = '\0';
241 diff_location[OS_MAXSTR] = '\0';
242 old_tmp[OS_MAXSTR] = '\0';
243 new_tmp[OS_MAXSTR] = '\0';
244 diff_tmp[OS_MAXSTR] = '\0';
245 diff_cmd[OS_MAXSTR] = '\0';
246 md5sum_new[0] = '\0';
247 md5sum_old[0] = '\0';
258 /* If the file is not there, rename new location to last location */
259 if (OS_MD5_File(old_location, md5sum_old, OS_BINARY) != 0) {
260 seechanges_createpath(old_location);
261 if (seechanges_dupfile(filename, old_location) != 1) {
262 merror(RENAME_ERROR, ARGV0, filename, old_location, errno, strerror(errno));
267 /* Get md5sum of the new file */
268 if (OS_MD5_File(filename, md5sum_new, OS_BINARY) != 0) {
272 /* If they match, keep the old file and remove the new */
273 if (strcmp(md5sum_new, md5sum_old) == 0) {
277 /* Save the old file at timestamp and rename new to last */
278 old_date_of_change = File_DateofChange(old_location);
283 "%s/local/%s/state.%d",
286 (int)old_date_of_change
289 /* Saving the old file at timestamp and renaming new to last. */
290 old_date_of_change = File_DateofChange(old_location);
294 sizeof(tmp_location),
295 "%s/local/%s/state.%d",
298 (int)old_date_of_change
302 if((rename(old_location, tmp_location)) < 0) {
303 merror("%s: ERROR rename of %s failed: %s", ARGV0, old_location, strerror(errno));
305 if(seechanges_dupfile(filename, old_location) != 1)
307 merror("%s: ERROR: Unable to create snapshot for %s",ARGV0, filename);
311 if (seechanges_dupfile(filename, old_location) != 1) {
312 merror("%s: ERROR: Unable to create snapshot for %s", ARGV0, filename);
316 new_date_of_change = File_DateofChange(old_location);
318 /* Create file names */
322 "%s/%s/syscheck-changes-%s-%d",
326 (int)old_date_of_change
332 "%s/%s/syscheck-changes-%s-%d",
336 (int)new_date_of_change
342 "%s/%s/syscheck-changes-%s-%d-%s-%d",
346 (int)old_date_of_change,
348 (int)new_date_of_change
350 /* Create diff location */
354 "%s/local/%s/diff.%d",
357 (int)new_date_of_change
360 /* Create symlinks */
361 if (symlink(old_location, old_tmp) == -1) {
362 merror(LINK_ERROR, ARGV0, old_location, old_tmp, errno, strerror(errno));
366 if (symlink(tmp_location, new_tmp) == -1) {
367 merror(LINK_ERROR, ARGV0, tmp_location, new_tmp, errno, strerror(errno));
371 if (symlink(diff_location, diff_tmp) == -1) {
372 merror(LINK_ERROR, ARGV0, diff_location, diff_tmp, errno, strerror(errno));
376 if (is_nodiff((filename))) {
377 /* Dont leak sensible data with a diff hanging around */
379 char* nodiff_message = "<Diff truncated because nodiff option>";
380 fdiff = fopen(diff_location, "w");
382 merror("%s: ERROR: Unable to open file for writing `%s`", ARGV0, diff_location);
385 fwrite(nodiff_message, strlen(nodiff_message) + 1, 1, fdiff);
394 "diff \"%s\" \"%s\" > \"%s\" 2> /dev/null",
400 if (system(diff_cmd) != 256) {
401 merror("%s: ERROR: Unable to run `%s`", ARGV0, diff_cmd);
418 return (gen_diff_alert(filename, new_date_of_change));