novi upstream verzije 2.8.3
[ossec-hids.git] / src / syscheckd / run_check.c
1 /* @(#) $Id: ./src/syscheckd/run_check.c, 2011/09/08 dcid Exp $
2  */
3
4 /* Copyright (C) 2010 Trend Micro Inc.
5  * All right reserved.
6  *
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
10  * Foundation
11  */
12
13
14 /* SCHED_BATCH is Linux specific and is only picked up with _GNU_SOURCE */
15 #ifdef __linux__
16         #define _GNU_SOURCE
17         #include <sched.h>
18 #endif
19
20 #include "shared.h"
21 #include "syscheck.h"
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"
25
26 #include "rootcheck/rootcheck.h"
27
28
29 /** Prototypes **/
30 int c_read_file(char *file_name, char *oldsum, char *newsum);
31
32
33 /* Send syscheck message.
34  * Send a message related to syscheck change/addition.
35  */
36 int send_syscheck_msg(char *msg)
37 {
38     if(SendMSG(syscheck.queue, msg, SYSCHECK, SYSCHECK_MQ) < 0)
39     {
40         merror(QUEUE_SEND, ARGV0);
41
42         if((syscheck.queue = StartMQ(DEFAULTQPATH,WRITE)) < 0)
43         {
44             ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
45         }
46
47         /* If we reach here, we can try to send it again */
48         SendMSG(syscheck.queue, msg, SYSCHECK, SYSCHECK_MQ);
49     }
50
51     return(0);
52 }
53
54
55
56 /* Send rootcheck message.
57  * Send a message related to rootcheck change/addition.
58  */
59 int send_rootcheck_msg(char *msg)
60 {
61     if(SendMSG(syscheck.queue, msg, ROOTCHECK, ROOTCHECK_MQ) < 0)
62     {
63         merror(QUEUE_SEND, ARGV0);
64
65         if((syscheck.queue = StartMQ(DEFAULTQPATH,WRITE)) < 0)
66         {
67             ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
68         }
69
70         /* If we reach here, we can try to send it again */
71         SendMSG(syscheck.queue, msg, ROOTCHECK, ROOTCHECK_MQ);
72     }
73
74     return(0);
75 }
76
77
78 /* Sends syscheck db to the server.
79  */
80 void send_sk_db()
81 {
82     /* Sending scan start message */
83     if(syscheck.dir[0])
84     {
85         merror("%s: INFO: Starting syscheck scan (forwarding database).", ARGV0);
86         send_rootcheck_msg("Starting syscheck scan.");
87     }
88     else
89     {
90         sleep(syscheck.tsleep +10);
91         return;
92     }
93
94     create_db(1);
95
96
97     /* Sending scan ending message */
98     sleep(syscheck.tsleep +10);
99
100     if(syscheck.dir[0])
101     {
102         merror("%s: INFO: Ending syscheck scan (forwarding database).", ARGV0);
103         send_rootcheck_msg("Ending syscheck scan.");
104     }
105 }
106
107
108
109 /* start_daemon
110  * Run periodicaly the integrity checking
111  */
112 void start_daemon()
113 {
114     int day_scanned = 0;
115     int curr_day = 0;
116
117     time_t curr_time = 0;
118
119     time_t prev_time_rk = 0;
120     time_t prev_time_sk = 0;
121
122     char curr_hour[12];
123
124     struct tm *p;
125
126
127     /* To be used by select. */
128     #ifdef USEINOTIFY
129     struct timeval selecttime;
130     fd_set rfds;
131     #endif
132
133
134     /*
135      * SCHED_BATCH forces the kernel to assume this is a cpu intensive
136      * process
137      * and gives it a lower priority. This keeps ossec-syscheckd
138      * from reducing
139      * the interactity of an ssh session when checksumming large files.
140      * This is available in kernel flavors >= 2.6.16
141      */
142     #ifdef SCHED_BATCH
143     struct sched_param pri;
144     int status;
145
146     pri.sched_priority = 0;
147     status = sched_setscheduler(0, SCHED_BATCH, &pri);
148
149     debug1("%s: Setting SCHED_BATCH returned: %d", ARGV0, status);
150     #endif
151
152
153     #ifdef DEBUG
154     verbose("%s: Starting daemon ..",ARGV0);
155     #endif
156
157
158
159     /* Some time to settle */
160     memset(curr_hour, '\0', 12);
161     sleep(syscheck.tsleep * 10);
162
163
164
165     /* If the scan time/day is set, reset the
166      * syscheck.time/rootcheck.time
167      */
168     if(syscheck.scan_time || syscheck.scan_day)
169     {
170         /* At least once a week. */
171         syscheck.time = 604800;
172         rootcheck.time = 604800;
173     }
174
175
176     /* Will create the db to store syscheck data */
177     if(syscheck.scan_on_start)
178     {
179         sleep(syscheck.tsleep * 15);
180         send_sk_db();
181     }
182     else
183     {
184         prev_time_rk = time(0);
185     }
186
187
188
189     /* Before entering in daemon mode itself */
190     prev_time_sk = time(0);
191     sleep(syscheck.tsleep * 10);
192
193
194     /* If the scan_time or scan_day is set, we need to handle the
195      * current day/time on the loop.
196      */
197     if(syscheck.scan_time || syscheck.scan_day)
198     {
199         curr_time = time(0);
200         p = localtime(&curr_time);
201
202
203         /* Assign hour/min/sec values */
204         snprintf(curr_hour, 9, "%02d:%02d:%02d",
205                 p->tm_hour,
206                 p->tm_min,
207                 p->tm_sec);
208
209
210         curr_day = p->tm_mday;
211
212
213
214         if(syscheck.scan_time && syscheck.scan_day)
215         {
216             if((OS_IsAfterTime(curr_hour, syscheck.scan_time)) &&
217                (OS_IsonDay(p->tm_wday, syscheck.scan_day)))
218             {
219                 day_scanned = 1;
220             }
221         }
222
223         else if(syscheck.scan_time)
224         {
225             if(OS_IsAfterTime(curr_hour, syscheck.scan_time))
226             {
227                 day_scanned = 1;
228             }
229         }
230         else if(syscheck.scan_day)
231         {
232             if(OS_IsonDay(p->tm_wday, syscheck.scan_day))
233             {
234                 day_scanned = 1;
235             }
236         }
237     }
238
239
240     /* Checking every SYSCHECK_WAIT */
241     while(1)
242     {
243         int run_now = 0;
244         curr_time = time(0);
245
246
247         /* Checking if syscheck should be restarted, */
248         run_now = os_check_restart_syscheck();
249
250
251         /* Checking if a day_time or scan_time is set. */
252         if(syscheck.scan_time || syscheck.scan_day)
253         {
254             p = localtime(&curr_time);
255
256
257             /* Day changed. */
258             if(curr_day != p->tm_mday)
259             {
260                 day_scanned = 0;
261                 curr_day = p->tm_mday;
262             }
263
264
265             /* Checking for the time of the scan. */
266             if(!day_scanned && syscheck.scan_time && syscheck.scan_day)
267             {
268                 /* Assign hour/min/sec values */
269                 snprintf(curr_hour, 9, "%02d:%02d:%02d",
270                                     p->tm_hour, p->tm_min, p->tm_sec);
271
272                 if((OS_IsAfterTime(curr_hour, syscheck.scan_time)) &&
273                    (OS_IsonDay(p->tm_wday, syscheck.scan_day)))
274                 {
275                     day_scanned = 1;
276                     run_now = 1;
277                 }
278             }
279
280             else if(!day_scanned && syscheck.scan_time)
281             {
282                 /* Assign hour/min/sec values */
283                 snprintf(curr_hour, 9, "%02d:%02d:%02d",
284                                     p->tm_hour, p->tm_min, p->tm_sec);
285
286                 if(OS_IsAfterTime(curr_hour, syscheck.scan_time))
287                 {
288                     run_now = 1;
289                     day_scanned = 1;
290                 }
291             }
292
293             /* Checking for the day of the scan. */
294             else if(!day_scanned && syscheck.scan_day)
295             {
296                 if(OS_IsonDay(p->tm_wday, syscheck.scan_day))
297                 {
298                     run_now = 1;
299                     day_scanned = 1;
300                 }
301             }
302         }
303
304
305
306         /* If time elapsed is higher than the rootcheck_time,
307          * run it.
308          */
309         if(syscheck.rootcheck)
310         {
311             if(((curr_time - prev_time_rk) > rootcheck.time) || run_now)
312             {
313                 run_rk_check();
314                 prev_time_rk = time(0);
315             }
316         }
317
318
319         /* If time elapsed is higher than the syscheck time,
320          * run syscheck time.
321          */
322         if(((curr_time - prev_time_sk) > syscheck.time) || run_now)
323         {
324             /* We need to create the db, if scan on start is not set. */
325             if(syscheck.scan_on_start == 0)
326             {
327                 sleep(syscheck.tsleep * 10);
328                 send_sk_db();
329                 sleep(syscheck.tsleep * 10);
330
331                 syscheck.scan_on_start = 1;
332             }
333
334
335             else
336             {
337                 /* Sending scan start message */
338                 if(syscheck.dir[0])
339                 {
340                     merror("%s: INFO: Starting syscheck scan.", ARGV0);
341                     send_rootcheck_msg("Starting syscheck scan.");
342                 }
343
344
345                 #ifdef WIN32
346                 /* Checking for registry changes on Windows */
347                 os_winreg_check();
348                 #endif
349
350
351                 /* Checking for changes */
352                 run_dbcheck();
353             }
354
355
356             /* Sending scan ending message */
357             sleep(syscheck.tsleep + 20);
358             if(syscheck.dir[0])
359             {
360                 merror("%s: INFO: Ending syscheck scan.", ARGV0);
361                 send_rootcheck_msg("Ending syscheck scan.");
362             }
363
364
365
366             /* Sending database completed message */
367             send_syscheck_msg(HC_SK_DB_COMPLETED);
368             debug2("%s: DEBUG: Sending database completed message.", ARGV0);
369
370
371             prev_time_sk = time(0);
372         }
373
374
375         #ifdef USEINOTIFY
376         if(syscheck.realtime && (syscheck.realtime->fd >= 0))
377         {
378             selecttime.tv_sec = SYSCHECK_WAIT;
379             selecttime.tv_usec = 0;
380
381             /* zero-out the fd_set */
382             FD_ZERO (&rfds);
383
384             FD_SET(syscheck.realtime->fd, &rfds);
385
386             run_now = select(syscheck.realtime->fd + 1, &rfds,
387                              NULL, NULL, &selecttime);
388             if(run_now < 0)
389             {
390                 merror("%s: ERROR: Select failed (for realtime fim).", ARGV0);
391                 sleep(SYSCHECK_WAIT);
392             }
393             else if(run_now == 0)
394             {
395                 /* Timeout. */
396             }
397             else if (FD_ISSET (syscheck.realtime->fd, &rfds))
398             {
399                 realtime_process();
400             }
401         }
402         else
403         {
404             sleep(SYSCHECK_WAIT);
405         }
406
407         #elif WIN32
408         if(syscheck.realtime && (syscheck.realtime->fd >= 0))
409         {
410             run_now = WaitForSingleObjectEx(syscheck.realtime->evt, SYSCHECK_WAIT * 1000, TRUE);
411             if(run_now == WAIT_FAILED)
412             {
413                 merror("%s: ERROR: WaitForSingleObjectEx failed (for realtime fim).", ARGV0);
414                 sleep(SYSCHECK_WAIT);
415             }
416             else
417             {
418                 sleep(1);
419             }
420         }
421         else
422         {
423             sleep(SYSCHECK_WAIT);
424         }
425
426
427         #else
428         sleep(SYSCHECK_WAIT);
429         #endif
430     }
431 }
432
433
434
435
436 /* c_read_file
437  * Read file information and return a pointer
438  * to the checksum
439  */
440 int c_read_file(char *file_name, char *oldsum, char *newsum)
441 {
442     int size = 0, perm = 0, owner = 0, group = 0, md5sum = 0, sha1sum = 0;
443
444     struct stat statbuf;
445
446     os_md5 mf_sum;
447     os_sha1 sf_sum;
448
449
450     /* Cleaning sums */
451     strncpy(mf_sum, "xxx", 4);
452     strncpy(sf_sum, "xxx", 4);
453
454
455
456     /* Stating the file */
457     #ifdef WIN32
458     if(stat(file_name, &statbuf) < 0)
459     #else
460     if(lstat(file_name, &statbuf) < 0)
461     #endif
462     {
463         char alert_msg[912 +2];
464
465         alert_msg[912 +1] = '\0';
466         snprintf(alert_msg, 912,"-1 %s", file_name);
467         send_syscheck_msg(alert_msg);
468
469         return(-1);
470     }
471
472     /* Getting the old sum values */
473
474     /* size */
475     if(oldsum[0] == '+')
476         size = 1;
477
478     /* perm */
479     if(oldsum[1] == '+')
480         perm = 1;
481
482     /* owner */
483     if(oldsum[2] == '+')
484         owner = 1;
485
486     /* group */
487     if(oldsum[3] == '+')
488         group = 1;
489
490     /* md5 sum */
491     if(oldsum[4] == '+')
492         md5sum = 1;
493
494     /* sha1 sum */
495     if(oldsum[5] == '+')
496         sha1sum = 1;
497
498     else if(oldsum[5] == 's')
499     {
500         sha1sum = 1;
501     }
502     else if(oldsum[5] == 'n')
503     {
504         sha1sum = 0;
505     }
506
507
508     /* Generating new checksum */
509     #ifdef WIN32
510     if(S_ISREG(statbuf.st_mode))
511     #else
512     if(S_ISREG(statbuf.st_mode))
513     #endif
514     {
515         if(sha1sum || md5sum)
516         {
517             /* Generating checksums of the file. */
518             if(OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum) < 0)
519             {
520                 strncpy(sf_sum, "xxx", 4);
521                 strncpy(mf_sum, "xxx", 4);
522             }
523         }
524     }
525     #ifndef WIN32
526     /* If it is a link, we need to check if the actual file is valid. */
527     else if(S_ISLNK(statbuf.st_mode))
528     {
529         struct stat statbuf_lnk;
530         if(stat(file_name, &statbuf_lnk) == 0)
531         {
532             if(S_ISREG(statbuf_lnk.st_mode))
533             {
534                 if(sha1sum || md5sum)
535                 {
536                     /* Generating checksums of the file. */
537                     if(OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum) < 0)
538                     {
539                         strncpy(sf_sum, "xxx", 4);
540                         strncpy(mf_sum, "xxx", 4);
541                     }
542                 }
543             }
544         }
545     }
546     #endif
547
548     newsum[0] = '\0';
549     newsum[255] = '\0';
550     /* chris: changed st_size int to long */
551     snprintf(newsum,255,"%ld:%d:%d:%d:%s:%s",
552             size == 0?0:(long)statbuf.st_size,
553             perm == 0?0:(int)statbuf.st_mode,
554             owner== 0?0:(int)statbuf.st_uid,
555             group== 0?0:(int)statbuf.st_gid,
556             md5sum   == 0?"xxx":mf_sum,
557             sha1sum  == 0?"xxx":sf_sum);
558
559     return(0);
560 }
561
562 /* EOF */