/* Periodically run the integrity checker */ void start_daemon() { int day_scanned = 0; int curr_day = 0; time_t curr_time = 0; time_t prev_time_rk = 0; time_t prev_time_sk = 0; char curr_hour[12]; struct tm *p; #ifdef INOTIFY_ENABLED /* To be used by select */ struct timeval selecttime; fd_set rfds; #endif /* SCHED_BATCH forces the kernel to assume this is a cpu intensive * process and gives it a lower priority. This keeps ossec-syscheckd * from reducing the interactity of an ssh session when checksumming * large files. This is available in kernel flavors >= 2.6.16. */ #ifdef SCHED_BATCH struct sched_param pri; int status; pri.sched_priority = 0; status = sched_setscheduler(0, SCHED_BATCH, &pri); debug1("%s: Setting SCHED_BATCH returned: %d", ARGV0, status); #endif #ifdef DEBUG verbose("%s: Starting daemon ..", ARGV0); #endif /* Some time to settle */ memset(curr_hour, '\0', 12); sleep(syscheck.tsleep * 10); /* If the scan time/day is set, reset the * syscheck.time/rootcheck.time */ if (syscheck.scan_time || syscheck.scan_day) { /* At least once a week */ syscheck.time = 604800; rootcheck.time = 604800; } /* Will create the db to store syscheck data */ if (syscheck.scan_on_start) { sleep(syscheck.tsleep * 15); send_sk_db(); } else { prev_time_rk = time(0); } /* Before entering in daemon mode itself */ prev_time_sk = time(0); sleep(syscheck.tsleep * 10); /* If the scan_time or scan_day is set, we need to handle the * current day/time on the loop. */ if (syscheck.scan_time || syscheck.scan_day) { curr_time = time(0); p = localtime(&curr_time); /* Assign hour/min/sec values */ snprintf(curr_hour, 9, "%02d:%02d:%02d", p->tm_hour, p->tm_min, p->tm_sec); curr_day = p->tm_mday; if (syscheck.scan_time && syscheck.scan_day) { if ((OS_IsAfterTime(curr_hour, syscheck.scan_time)) && (OS_IsonDay(p->tm_wday, syscheck.scan_day))) { day_scanned = 1; } } else if (syscheck.scan_time) { if (OS_IsAfterTime(curr_hour, syscheck.scan_time)) { day_scanned = 1; } } else if (syscheck.scan_day) { if (OS_IsonDay(p->tm_wday, syscheck.scan_day)) { day_scanned = 1; } } } /* Check every SYSCHECK_WAIT */ while (1) { int run_now = 0; curr_time = time(0); /* Check if syscheck should be restarted */ run_now = os_check_restart_syscheck(); /* Check if a day_time or scan_time is set */ if (syscheck.scan_time || syscheck.scan_day) { p = localtime(&curr_time); /* Day changed */ if (curr_day != p->tm_mday) { day_scanned = 0; curr_day = p->tm_mday; } /* Check for the time of the scan */ if (!day_scanned && syscheck.scan_time && syscheck.scan_day) { /* Assign hour/min/sec values */ snprintf(curr_hour, 9, "%02d:%02d:%02d", p->tm_hour, p->tm_min, p->tm_sec); if ((OS_IsAfterTime(curr_hour, syscheck.scan_time)) && (OS_IsonDay(p->tm_wday, syscheck.scan_day))) { day_scanned = 1; run_now = 1; } } else if (!day_scanned && syscheck.scan_time) { /* Assign hour/min/sec values */ snprintf(curr_hour, 9, "%02d:%02d:%02d", p->tm_hour, p->tm_min, p->tm_sec); if (OS_IsAfterTime(curr_hour, syscheck.scan_time)) { run_now = 1; day_scanned = 1; } } else if (!day_scanned && syscheck.scan_day) { /* Check for the day of the scan */ if (OS_IsonDay(p->tm_wday, syscheck.scan_day)) { run_now = 1; day_scanned = 1; } } } /* If time elapsed is higher than the rootcheck_time, run it */ if (syscheck.rootcheck) { if (((curr_time - prev_time_rk) > rootcheck.time) || run_now) { run_rk_check(); prev_time_rk = time(0); } } /* If time elapsed is higher than the syscheck time, run syscheck time */ if (((curr_time - prev_time_sk) > syscheck.time) || run_now) { if (syscheck.scan_on_start == 0) { /* Need to create the db if scan on start is not set */ sleep(syscheck.tsleep * 10); send_sk_db(); sleep(syscheck.tsleep * 10); syscheck.scan_on_start = 1; } else { /* Send scan start message */ if (syscheck.dir[0]) { merror("%s: INFO: Starting syscheck scan.", ARGV0); send_rootcheck_msg("Starting syscheck scan."); } #ifdef WIN32 /* Check for registry changes on Windows */ os_winreg_check(); #endif /* Check for changes */ run_dbcheck(); } /* Send scan ending message */ sleep(syscheck.tsleep + 20); if (syscheck.dir[0]) { merror("%s: INFO: Ending syscheck scan.", ARGV0); send_rootcheck_msg("Ending syscheck scan."); } /* Send database completed message */ send_syscheck_msg(HC_SK_DB_COMPLETED); debug2("%s: DEBUG: Sending database completed message.", ARGV0); prev_time_sk = time(0); } #ifdef INOTIFY_ENABLED if (syscheck.realtime && (syscheck.realtime->fd >= 0)) { selecttime.tv_sec = SYSCHECK_WAIT; selecttime.tv_usec = 0; /* zero-out the fd_set */ FD_ZERO (&rfds); FD_SET(syscheck.realtime->fd, &rfds); run_now = select(syscheck.realtime->fd + 1, &rfds, NULL, NULL, &selecttime); if (run_now < 0) { merror("%s: ERROR: Select failed (for realtime fim).", ARGV0); sleep(SYSCHECK_WAIT); } else if (run_now == 0) { /* Timeout */ } else if (FD_ISSET (syscheck.realtime->fd, &rfds)) { realtime_process(); } } else { sleep(SYSCHECK_WAIT); } #elif defined(WIN32) if (syscheck.realtime && (syscheck.realtime->fd >= 0)) { run_now = WaitForSingleObjectEx(syscheck.realtime->evt, SYSCHECK_WAIT * 1000, TRUE); if (run_now == WAIT_FAILED) { merror("%s: ERROR: WaitForSingleObjectEx failed (for realtime fim).", ARGV0); sleep(SYSCHECK_WAIT); } else { sleep(1); } } else { sleep(SYSCHECK_WAIT); } #else sleep(SYSCHECK_WAIT); #endif } }
/* Read and generate the integrity data of a file */ static int read_file(const char *file_name, int opts, OSMatch *restriction) { char *buf; char sha1s = '+'; struct stat statbuf; /* Check if the file should be ignored */ if (syscheck.ignore) { int i = 0; while (syscheck.ignore[i] != NULL) { if (strncasecmp(syscheck.ignore[i], file_name, strlen(syscheck.ignore[i])) == 0) { return (0); } i++; } } /* Check in the regex entry */ if (syscheck.ignore_regex) { int i = 0; while (syscheck.ignore_regex[i] != NULL) { if (OSMatch_Execute(file_name, strlen(file_name), syscheck.ignore_regex[i])) { return (0); } i++; } } #ifdef WIN32 /* Win32 does not have lstat */ if (stat(file_name, &statbuf) < 0) #else if (lstat(file_name, &statbuf) < 0) #endif { if(errno == ENOTDIR){ /*Deletion message sending*/ char alert_msg[PATH_MAX+4]; alert_msg[PATH_MAX + 3] = '\0'; snprintf(alert_msg, PATH_MAX + 4, "-1 %s", file_name); send_syscheck_msg(alert_msg); return (0); }else{ merror("%s: Error accessing '%s'.", ARGV0, file_name); return (-1); } } if (S_ISDIR(statbuf.st_mode)) { #ifdef DEBUG verbose("%s: Reading dir: %s\n", ARGV0, file_name); #endif #ifdef WIN32 /* Directory links are not supported */ if (GetFileAttributes(file_name) & FILE_ATTRIBUTE_REPARSE_POINT) { merror("%s: WARN: Links are not supported: '%s'", ARGV0, file_name); return (-1); } #endif return (read_dir(file_name, opts, restriction)); } /* Restrict file types */ if (restriction) { if (!OSMatch_Execute(file_name, strlen(file_name), restriction)) { return (0); } } /* No S_ISLNK on Windows */ #ifdef WIN32 if (S_ISREG(statbuf.st_mode)) #else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) #endif { os_md5 mf_sum; os_sha1 sf_sum; os_sha1 sf_sum2; os_sha1 sf_sum3; /* Clean sums */ strncpy(mf_sum, "xxx", 4); strncpy(sf_sum, "xxx", 4); strncpy(sf_sum2, "xxx", 4); strncpy(sf_sum3, "xxx", 4); /* Generate checksums */ if ((opts & CHECK_MD5SUM) || (opts & CHECK_SHA1SUM)) { /* If it is a link, check if dest is valid */ #ifndef WIN32 if (S_ISLNK(statbuf.st_mode)) { struct stat statbuf_lnk; if (stat(file_name, &statbuf_lnk) == 0) { if (S_ISREG(statbuf_lnk.st_mode)) { if (OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum, OS_BINARY) < 0) { strncpy(mf_sum, "xxx", 4); strncpy(sf_sum, "xxx", 4); } } } } else if (OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum, OS_BINARY) < 0) #else if (OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum, OS_BINARY) < 0) #endif { strncpy(mf_sum, "xxx", 4); strncpy(sf_sum, "xxx", 4); } if (opts & CHECK_SEECHANGES) { sha1s = 's'; } } else { if (opts & CHECK_SEECHANGES) { sha1s = 'n'; } else { sha1s = '-'; } } buf = (char *) OSHash_Get(syscheck.fp, file_name); if (!buf) { char alert_msg[916 + 1]; /* to accommodate a long */ alert_msg[916] = '\0'; if (opts & CHECK_SEECHANGES) { char *alertdump = seechanges_addfile(file_name); if (alertdump) { free(alertdump); alertdump = NULL; } } snprintf(alert_msg, 916, "%c%c%c%c%c%c%c%c%ld:%d:%d:%d:%s:%s:%s:%s:%ld:%ld", opts & CHECK_SIZE ? '+' : '-', opts & CHECK_PERM ? '+' : '-', opts & CHECK_OWNER ? '+' : '-', opts & CHECK_GROUP ? '+' : '-', opts & CHECK_MD5SUM ? '+' : '-', sha1s, opts & CHECK_MTIME ? '+' : '-', opts & CHECK_INODE ? '+' : '-', opts & CHECK_SIZE ? (long)statbuf.st_size : 0, opts & CHECK_PERM ? (int)statbuf.st_mode : 0, opts & CHECK_OWNER ? (int)statbuf.st_uid : 0, opts & CHECK_GROUP ? (int)statbuf.st_gid : 0, opts & CHECK_MD5SUM ? mf_sum : "xxx", opts & CHECK_SHA1SUM ? sf_sum : "xxx", opts & CHECK_OWNER ? get_user(file_name, statbuf.st_uid) : "", opts & CHECK_GROUP ? get_group(statbuf.st_gid) : "", opts & CHECK_MTIME ? (long)statbuf.st_mtime : 0, opts & CHECK_INODE ? (long)statbuf.st_ino : 0); if (OSHash_Add(syscheck.fp, file_name, strdup(alert_msg)) <= 0) { merror("%s: ERROR: Unable to add file to db: %s", ARGV0, file_name); } /* Send the new checksum to the analysis server */ alert_msg[916] = '\0'; snprintf(alert_msg, 916, "%ld:%d:%d:%d:%s:%s:%s:%s:%ld:%ld %s", opts & CHECK_SIZE ? (long)statbuf.st_size : 0, opts & CHECK_PERM ? (int)statbuf.st_mode : 0, opts & CHECK_OWNER ? (int)statbuf.st_uid : 0, opts & CHECK_GROUP ? (int)statbuf.st_gid : 0, opts & CHECK_MD5SUM ? mf_sum : "xxx", opts & CHECK_SHA1SUM ? sf_sum : "xxx", opts & CHECK_OWNER ? get_user(file_name, statbuf.st_uid) : "", opts & CHECK_GROUP ? get_group(statbuf.st_gid) : "", opts & CHECK_MTIME ? (long)statbuf.st_mtime : 0, opts & CHECK_INODE ? (long)statbuf.st_ino : 0, file_name); send_syscheck_msg(alert_msg); } else { char alert_msg[OS_MAXSTR + 1]; char c_sum[256 + 2]; c_sum[0] = '\0'; c_sum[256] = '\0'; alert_msg[0] = '\0'; alert_msg[OS_MAXSTR] = '\0'; /* If it returns < 0, we have already alerted */ if (c_read_file(file_name, buf, c_sum) < 0) { return (0); } if (strcmp(c_sum, buf + 6) != 0) { /* Send the new checksum to the analysis server */ alert_msg[OS_MAXSTR] = '\0'; char *fullalert = NULL; if (buf[5] == 's' || buf[5] == 'n') { fullalert = seechanges_addfile(file_name); if (fullalert) { snprintf(alert_msg, OS_MAXSTR, "%s %s\n%s", c_sum, file_name, fullalert); free(fullalert); fullalert = NULL; } else { snprintf(alert_msg, 916, "%s %s", c_sum, file_name); } } else { snprintf(alert_msg, 916, "%s %s", c_sum, file_name); } send_syscheck_msg(alert_msg); } } /* Sleep here too */ if (__counter >= (syscheck.sleep_after)) { sleep(syscheck.tsleep); __counter = 0; } __counter++; #ifdef DEBUG verbose("%s: file '%s %s'", ARGV0, file_name, mf_sum); #endif } else { #ifdef DEBUG verbose("%s: *** IRREG file: '%s'\n", ARGV0, file_name); #endif } return (0); }
/* Read file information and return a pointer to the checksum */ int c_read_file(const char *file_name, const char *oldsum, char *newsum) { int size = 0, perm = 0, owner = 0, group = 0, md5sum = 0, sha1sum = 0; struct stat statbuf; os_md5 mf_sum; os_sha1 sf_sum; /* Clean sums */ strncpy(mf_sum, "xxx", 4); strncpy(sf_sum, "xxx", 4); /* Stat the file */ #ifdef WIN32 if (stat(file_name, &statbuf) < 0) #else if (lstat(file_name, &statbuf) < 0) #endif { char alert_msg[912 + 2]; alert_msg[912 + 1] = '\0'; snprintf(alert_msg, 912, "-1 %s", file_name); send_syscheck_msg(alert_msg); return (-1); } /* Get the old sum values */ /* size */ if (oldsum[0] == '+') { size = 1; } /* perm */ if (oldsum[1] == '+') { perm = 1; } /* owner */ if (oldsum[2] == '+') { owner = 1; } /* group */ if (oldsum[3] == '+') { group = 1; } /* md5 sum */ if (oldsum[4] == '+') { md5sum = 1; } /* sha1 sum */ if (oldsum[5] == '+') { sha1sum = 1; } else if (oldsum[5] == 's') { sha1sum = 1; } else if (oldsum[5] == 'n') { sha1sum = 0; } /* Generate new checksum */ #ifdef WIN32 if (S_ISREG(statbuf.st_mode)) #else if (S_ISREG(statbuf.st_mode)) #endif { if (sha1sum || md5sum) { /* Generate checksums of the file */ if (OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum) < 0) { strncpy(sf_sum, "xxx", 4); strncpy(mf_sum, "xxx", 4); } } } #ifndef WIN32 /* If it is a link, check if the actual file is valid */ else if (S_ISLNK(statbuf.st_mode)) { struct stat statbuf_lnk; if (stat(file_name, &statbuf_lnk) == 0) { if (S_ISREG(statbuf_lnk.st_mode)) { if (sha1sum || md5sum) { /* Generate checksums of the file */ if (OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum) < 0) { strncpy(sf_sum, "xxx", 4); strncpy(mf_sum, "xxx", 4); } } } } } #endif newsum[0] = '\0'; newsum[255] = '\0'; snprintf(newsum, 255, "%ld:%d:%d:%d:%s:%s", size == 0 ? 0 : (long)statbuf.st_size, perm == 0 ? 0 : (int)statbuf.st_mode, owner == 0 ? 0 : (int)statbuf.st_uid, group == 0 ? 0 : (int)statbuf.st_gid, md5sum == 0 ? "xxx" : mf_sum, sha1sum == 0 ? "xxx" : sf_sum); return (0); }