1 /* @(#) $Id: ./src/syscheckd/run_check.c, 2011/09/08 dcid Exp $
4 /* Copyright (C) 2010 Trend Micro Inc.
7 * This program is a free software; you can redistribute it
8 * and/or modify it under the terms of the GNU General Public
9 * License (version 2) as published by the FSF - Free Software
14 /* SCHED_BATCH is Linux specific and is only picked up with _GNU_SOURCE */
22 #include "os_crypto/md5/md5_op.h"
23 #include "os_crypto/sha1/sha1_op.h"
24 #include "os_crypto/md5_sha1/md5_sha1_op.h"
26 #include "rootcheck/rootcheck.h"
30 int c_read_file(char *file_name, char *oldsum, char *newsum);
33 /* Send syscheck message.
34 * Send a message related to syscheck change/addition.
36 int send_syscheck_msg(char *msg)
38 if(SendMSG(syscheck.queue, msg, SYSCHECK, SYSCHECK_MQ) < 0)
40 merror(QUEUE_SEND, ARGV0);
42 if((syscheck.queue = StartMQ(DEFAULTQPATH,WRITE)) < 0)
44 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
47 /* If we reach here, we can try to send it again */
48 SendMSG(syscheck.queue, msg, SYSCHECK, SYSCHECK_MQ);
56 /* Send rootcheck message.
57 * Send a message related to rootcheck change/addition.
59 int send_rootcheck_msg(char *msg)
61 if(SendMSG(syscheck.queue, msg, ROOTCHECK, ROOTCHECK_MQ) < 0)
63 merror(QUEUE_SEND, ARGV0);
65 if((syscheck.queue = StartMQ(DEFAULTQPATH,WRITE)) < 0)
67 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
70 /* If we reach here, we can try to send it again */
71 SendMSG(syscheck.queue, msg, ROOTCHECK, ROOTCHECK_MQ);
78 /* Sends syscheck db to the server.
82 /* Sending scan start message */
85 merror("%s: INFO: Starting syscheck scan (forwarding database).", ARGV0);
86 send_rootcheck_msg("Starting syscheck scan.");
90 sleep(syscheck.tsleep +10);
97 /* Sending scan ending message */
98 sleep(syscheck.tsleep +10);
102 merror("%s: INFO: Ending syscheck scan (forwarding database).", ARGV0);
103 send_rootcheck_msg("Ending syscheck scan.");
110 * Run periodicaly the integrity checking
117 time_t curr_time = 0;
119 time_t prev_time_rk = 0;
120 time_t prev_time_sk = 0;
127 /* To be used by select. */
129 struct timeval selecttime;
135 * SCHED_BATCH forces the kernel to assume this is a cpu intensive
137 * and gives it a lower priority. This keeps ossec-syscheckd
139 * the interactity of an ssh session when checksumming large files.
140 * This is available in kernel flavors >= 2.6.16
143 struct sched_param pri;
146 pri.sched_priority = 0;
147 status = sched_setscheduler(0, SCHED_BATCH, &pri);
149 debug1("%s: Setting SCHED_BATCH returned: %d", ARGV0, status);
154 verbose("%s: Starting daemon ..",ARGV0);
159 /* Some time to settle */
160 memset(curr_hour, '\0', 12);
161 sleep(syscheck.tsleep * 10);
165 /* If the scan time/day is set, reset the
166 * syscheck.time/rootcheck.time
168 if(syscheck.scan_time || syscheck.scan_day)
170 /* At least once a week. */
171 syscheck.time = 604800;
172 rootcheck.time = 604800;
176 /* Will create the db to store syscheck data */
177 if(syscheck.scan_on_start)
179 sleep(syscheck.tsleep * 15);
184 prev_time_rk = time(0);
189 /* Before entering in daemon mode itself */
190 prev_time_sk = time(0);
191 sleep(syscheck.tsleep * 10);
194 /* If the scan_time or scan_day is set, we need to handle the
195 * current day/time on the loop.
197 if(syscheck.scan_time || syscheck.scan_day)
200 p = localtime(&curr_time);
203 /* Assign hour/min/sec values */
204 snprintf(curr_hour, 9, "%02d:%02d:%02d",
210 curr_day = p->tm_mday;
214 if(syscheck.scan_time && syscheck.scan_day)
216 if((OS_IsAfterTime(curr_hour, syscheck.scan_time)) &&
217 (OS_IsonDay(p->tm_wday, syscheck.scan_day)))
223 else if(syscheck.scan_time)
225 if(OS_IsAfterTime(curr_hour, syscheck.scan_time))
230 else if(syscheck.scan_day)
232 if(OS_IsonDay(p->tm_wday, syscheck.scan_day))
240 /* Checking every SYSCHECK_WAIT */
247 /* Checking if syscheck should be restarted, */
248 run_now = os_check_restart_syscheck();
251 /* Checking if a day_time or scan_time is set. */
252 if(syscheck.scan_time || syscheck.scan_day)
254 p = localtime(&curr_time);
258 if(curr_day != p->tm_mday)
261 curr_day = p->tm_mday;
265 /* Checking for the time of the scan. */
266 if(!day_scanned && syscheck.scan_time && syscheck.scan_day)
268 if((OS_IsAfterTime(curr_hour, syscheck.scan_time)) &&
269 (OS_IsonDay(p->tm_wday, syscheck.scan_day)))
276 else if(!day_scanned && syscheck.scan_time)
278 /* Assign hour/min/sec values */
279 snprintf(curr_hour, 9, "%02d:%02d:%02d",
280 p->tm_hour, p->tm_min, p->tm_sec);
282 if(OS_IsAfterTime(curr_hour, syscheck.scan_time))
289 /* Checking for the day of the scan. */
290 else if(!day_scanned && syscheck.scan_day)
292 if(OS_IsonDay(p->tm_wday, syscheck.scan_day))
302 /* If time elapsed is higher than the rootcheck_time,
305 if(syscheck.rootcheck)
307 if(((curr_time - prev_time_rk) > rootcheck.time) || run_now)
310 prev_time_rk = time(0);
315 /* If time elapsed is higher than the syscheck time,
318 if(((curr_time - prev_time_sk) > syscheck.time) || run_now)
320 /* We need to create the db, if scan on start is not set. */
321 if(syscheck.scan_on_start == 0)
323 sleep(syscheck.tsleep * 10);
325 sleep(syscheck.tsleep * 10);
327 syscheck.scan_on_start = 1;
333 /* Sending scan start message */
336 merror("%s: INFO: Starting syscheck scan.", ARGV0);
337 send_rootcheck_msg("Starting syscheck scan.");
342 /* Checking for registry changes on Windows */
347 /* Checking for changes */
352 /* Sending scan ending message */
353 sleep(syscheck.tsleep + 20);
356 merror("%s: INFO: Ending syscheck scan.", ARGV0);
357 send_rootcheck_msg("Ending syscheck scan.");
362 /* Sending database completed message */
363 send_syscheck_msg(HC_SK_DB_COMPLETED);
364 debug2("%s: DEBUG: Sending database completed message.", ARGV0);
367 prev_time_sk = time(0);
372 if(syscheck.realtime && (syscheck.realtime->fd >= 0))
374 selecttime.tv_sec = SYSCHECK_WAIT;
375 selecttime.tv_usec = 0;
377 /* zero-out the fd_set */
380 FD_SET(syscheck.realtime->fd, &rfds);
382 run_now = select(syscheck.realtime->fd + 1, &rfds,
383 NULL, NULL, &selecttime);
386 merror("%s: ERROR: Select failed (for realtime fim).", ARGV0);
387 sleep(SYSCHECK_WAIT);
389 else if(run_now == 0)
393 else if (FD_ISSET (syscheck.realtime->fd, &rfds))
400 sleep(SYSCHECK_WAIT);
404 if(syscheck.realtime && (syscheck.realtime->fd >= 0))
406 run_now = WaitForSingleObjectEx(syscheck.realtime->evt, SYSCHECK_WAIT * 1000, TRUE);
407 if(run_now == WAIT_FAILED)
409 merror("%s: ERROR: WaitForSingleObjectEx failed (for realtime fim).", ARGV0);
410 sleep(SYSCHECK_WAIT);
419 sleep(SYSCHECK_WAIT);
424 sleep(SYSCHECK_WAIT);
433 * Read file information and return a pointer
436 int c_read_file(char *file_name, char *oldsum, char *newsum)
438 int size = 0, perm = 0, owner = 0, group = 0, md5sum = 0, sha1sum = 0, seechanges = 0;
447 strncpy(mf_sum, "xxx", 4);
448 strncpy(sf_sum, "xxx", 4);
452 /* Stating the file */
454 if(stat(file_name, &statbuf) < 0)
456 if(lstat(file_name, &statbuf) < 0)
459 char alert_msg[912 +2];
461 alert_msg[912 +1] = '\0';
462 snprintf(alert_msg, 912,"-1 %s", file_name);
463 send_syscheck_msg(alert_msg);
468 /* Getting the old sum values */
494 else if(oldsum[5] == 's')
499 else if(oldsum[5] == 'n')
506 /* Generating new checksum */
508 if(S_ISREG(statbuf.st_mode))
510 if(S_ISREG(statbuf.st_mode))
513 if(sha1sum || md5sum)
515 /* Generating checksums of the file. */
516 if(OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum) < 0)
518 strncpy(sf_sum, "xxx", 4);
519 strncpy(mf_sum, "xxx", 4);
524 /* If it is a link, we need to check if the actual file is valid. */
525 else if(S_ISLNK(statbuf.st_mode))
527 struct stat statbuf_lnk;
528 if(stat(file_name, &statbuf_lnk) == 0)
530 if(S_ISREG(statbuf_lnk.st_mode))
532 if(sha1sum || md5sum)
534 /* Generating checksums of the file. */
535 if(OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum) < 0)
537 strncpy(sf_sum, "xxx", 4);
538 strncpy(mf_sum, "xxx", 4);
548 snprintf(newsum,255,"%d:%d:%d:%d:%s:%s",
549 size == 0?0:(int)statbuf.st_size,
550 perm == 0?0:(int)statbuf.st_mode,
551 owner== 0?0:(int)statbuf.st_uid,
552 group== 0?0:(int)statbuf.st_gid,
553 md5sum == 0?"xxx":mf_sum,
554 sha1sum == 0?"xxx":sf_sum);