Imported Upstream version 2.5.1
[ossec-hids.git] / src / syscheckd / create_db.c
1 /* @(#) $Id$ */
2
3 /* Copyright (C) 2009 Trend Micro Inc.
4  * All right reserved.
5  *
6  * This program is a free software; you can redistribute it
7  * and/or modify it under the terms of the GNU General Public
8  * License (version 2) as published by the FSF - Free Software
9  * Foundation
10  *
11  * License details at the LICENSE file included with OSSEC or 
12  * online at: http://www.ossec.net/en/licensing.html
13  */
14
15
16 #include "shared.h"
17 #include "syscheck.h"
18 #include "os_crypto/md5/md5_op.h"
19 #include "os_crypto/sha1/sha1_op.h"
20 #include "os_crypto/md5_sha1/md5_sha1_op.h"
21
22
23 int __counter = 0;
24
25
26 /** Prototypes **/
27 int read_dir(char *dir_name, int opts, OSMatch *restriction);
28
29
30 /* int check_file(char *file_name)
31  * Checks if the file is already in the database.
32  */
33 int check_file(char *file_name)
34 {
35     if(OSHash_Get(syscheck.fp, file_name))
36     {
37         return(1);
38     }
39
40     /* New file */
41     sleep(1);
42     
43     debug2("%s: DEBUG: new file '%s'.", ARGV0, file_name);
44     return(0);
45 }
46
47
48
49 /* int read_file(char *file_name, int opts, int flag)
50  * Reads and generates the integrity data of a file.
51  */
52 int read_file(char *file_name, int opts, OSMatch *restriction)
53 {
54     char *buf;
55     char sha1s = '+';
56     struct stat statbuf;
57     
58
59     /* Checking if file is to be ignored */
60     if(syscheck.ignore)
61     {
62         int i = 0;
63         while(syscheck.ignore[i] != NULL)
64         {
65             if(strncasecmp(syscheck.ignore[i], file_name, 
66                            strlen(syscheck.ignore[i])) == 0)
67             {
68                 return(0);            
69             }
70
71             i++;
72         }
73     }
74
75     /* Checking in the regex entry */
76     if(syscheck.ignore_regex)
77     {
78         int i = 0;
79         while(syscheck.ignore_regex[i] != NULL)
80         {
81             if(OSMatch_Execute(file_name, strlen(file_name), 
82                                           syscheck.ignore_regex[i]))
83             {
84                 return(0);
85             }
86             i++;
87         }
88     }
89
90
91     /* Win32 does not have lstat */
92     #ifdef WIN32
93     if(stat(file_name, &statbuf) < 0)
94     #else
95     if(lstat(file_name, &statbuf) < 0)
96     #endif
97     {
98         merror("%s: Error accessing '%s'.",ARGV0, file_name);
99         return(-1);
100     }
101     
102     if(S_ISDIR(statbuf.st_mode))
103     {
104         #ifdef DEBUG
105         verbose("%s: Reading dir: %s\n",ARGV0, file_name);
106         #endif
107
108         return(read_dir(file_name, opts, restriction));
109     }
110
111
112     /* restricting file types. */
113     if(restriction)
114     {
115         if(!OSMatch_Execute(file_name, strlen(file_name), 
116                             restriction))
117         {
118             return(0);
119         }
120     }
121     
122     
123     /* No S_ISLNK on windows */
124     #ifdef WIN32
125     else if(S_ISREG(statbuf.st_mode))
126     #else
127     else if(S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode))
128     #endif    
129     {
130         os_md5 mf_sum;
131         os_sha1 sf_sum;
132         os_sha1 sf_sum2;
133         os_sha1 sf_sum3;
134
135
136         /* Cleaning sums */
137         strncpy(mf_sum, "xxx", 4);
138         strncpy(sf_sum, "xxx", 4);
139         strncpy(sf_sum2, "xxx", 4);
140         strncpy(sf_sum3, "xxx", 4);
141
142
143         /* Generating checksums. */
144         if((opts & CHECK_MD5SUM) || (opts & CHECK_SHA1SUM))
145         {
146             /* If it is a link, we need to check if dest is valid. */
147             #ifndef WIN32
148             if(S_ISLNK(statbuf.st_mode))
149             {
150                 struct stat statbuf_lnk;
151                 if(stat(file_name, &statbuf_lnk) == 0)
152                 {
153                     if(S_ISREG(statbuf_lnk.st_mode))
154                     {
155                         if(OS_MD5_SHA1_File(file_name, mf_sum, sf_sum) < 0)
156                         {
157                             strncpy(mf_sum, "xxx", 4);
158                             strncpy(sf_sum, "xxx", 4);
159                         }
160                     }
161                 }
162             }
163             else if(OS_MD5_SHA1_File(file_name, mf_sum, sf_sum) < 0)
164
165             #else
166             if(OS_MD5_SHA1_File(file_name, mf_sum, sf_sum) < 0)
167             #endif
168             
169             {
170                 strncpy(mf_sum, "xxx", 4);
171                 strncpy(sf_sum, "xxx", 4);
172
173             }
174
175             if(opts & CHECK_SEECHANGES)
176             {
177                 sha1s = 's';
178             }
179         }
180         else
181         {
182             if(opts & CHECK_SEECHANGES)
183                 sha1s = 'n';
184             else
185                 sha1s = '-';    
186         }
187         
188         
189         buf = OSHash_Get(syscheck.fp, file_name);
190         if(!buf)
191         {
192             char alert_msg[912 +1];
193            
194             alert_msg[912] = '\0';
195
196             if(opts & CHECK_SEECHANGES)
197             {
198                 char *alertdump = seechanges_addfile(file_name);
199                 if(alertdump)
200                 {
201                     free(alertdump);
202                     alertdump = NULL;
203                 }
204             }
205
206                    
207             snprintf(alert_msg, 912, "%c%c%c%c%c%c%d:%d:%d:%d:%s:%s",
208                 opts & CHECK_SIZE?'+':'-',
209                 opts & CHECK_PERM?'+':'-',
210                 opts & CHECK_OWNER?'+':'-',
211                 opts & CHECK_GROUP?'+':'-',
212                 opts & CHECK_MD5SUM?'+':'-',
213                 sha1s,
214                 opts & CHECK_SIZE?(int)statbuf.st_size:0,
215                 opts & CHECK_PERM?(int)statbuf.st_mode:0,
216                 opts & CHECK_OWNER?(int)statbuf.st_uid:0,
217                 opts & CHECK_GROUP?(int)statbuf.st_gid:0,
218                 opts & CHECK_MD5SUM?mf_sum:"xxx",
219                 opts & CHECK_SHA1SUM?sf_sum:"xxx");
220
221             if(OSHash_Add(syscheck.fp, strdup(file_name), strdup(alert_msg)) <= 0)
222             {
223                 merror("%s: ERROR: Unable to add file to db: %s", ARGV0, file_name);
224             }
225
226
227             /* Sending the new checksum to the analysis server */
228             alert_msg[912 +1] = '\0';
229             snprintf(alert_msg, 912, "%d:%d:%d:%d:%s:%s %s", 
230                      opts & CHECK_SIZE?(int)statbuf.st_size:0,
231                      opts & CHECK_PERM?(int)statbuf.st_mode:0,
232                      opts & CHECK_OWNER?(int)statbuf.st_uid:0,
233                      opts & CHECK_GROUP?(int)statbuf.st_gid:0,
234                      opts & CHECK_MD5SUM?mf_sum:"xxx",
235                      opts & CHECK_SHA1SUM?sf_sum:"xxx",
236                      file_name);
237             send_syscheck_msg(alert_msg);
238         }
239         else
240         {
241             char alert_msg[OS_MAXSTR +1];
242             char c_sum[256 +2];
243             
244             c_sum[0] = '\0';
245             c_sum[256] = '\0';
246             alert_msg[0] = '\0';
247             alert_msg[OS_MAXSTR] = '\0';
248
249             /* If it returns < 0, we will already have alerted. */
250             if(c_read_file(file_name, buf, c_sum) < 0)
251                 return(0);
252
253             if(strcmp(c_sum, buf+6) != 0)
254             {
255                 /* Sending the new checksum to the analysis server */
256                 char *fullalert = NULL;
257                 alert_msg[OS_MAXSTR] = '\0';
258                 if(buf[5] == 's' || buf[5] == 'n')
259                 {
260                     fullalert = seechanges_addfile(file_name);
261                     if(fullalert)
262                     {
263                         snprintf(alert_msg, OS_MAXSTR, "%s %s\n%s", c_sum, file_name, fullalert);
264                         free(fullalert);
265                         fullalert = NULL;
266                     }
267                     else
268                     {
269                         snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
270                     }
271                 }
272                 else
273                 {
274                     snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
275                 }
276                 send_syscheck_msg(alert_msg);
277             }
278         }
279         
280         
281         /* Sleeping in here too */
282         if(__counter >= (syscheck.sleep_after))
283         {
284             sleep(syscheck.tsleep);
285             __counter = 0;
286         }
287         __counter++;
288
289
290         #ifdef DEBUG 
291         verbose("%s: file '%s %s'",ARGV0, file_name, mf_sum);
292         #endif
293     }
294     else
295     {
296         #ifdef DEBUG
297         verbose("%s: *** IRREG file: '%s'\n",ARGV0,file_name);
298         #endif
299     }
300
301     return(0);
302 }
303
304
305 /* read_dir v0.1
306  *
307  */
308 int read_dir(char *dir_name, int opts, OSMatch *restriction)
309 {
310     int dir_size;
311    
312     char f_name[PATH_MAX +2]; 
313     DIR *dp;
314     
315         struct dirent *entry;
316
317     f_name[PATH_MAX +1] = '\0';
318         
319
320     /* Directory should be valid */
321     if((dir_name == NULL)||((dir_size = strlen(dir_name)) > PATH_MAX))
322     {
323         merror(NULL_ERROR, ARGV0);
324         
325         return(-1);
326     }
327     
328     
329     /* Opening the directory given */
330     dp = opendir(dir_name);
331         if(!dp)
332     {
333         if(errno == ENOTDIR)
334         {
335             if(read_file(dir_name, opts, restriction) == 0)
336                 return(0);
337         }
338         
339         #ifdef WIN32
340         int di = 0;
341         char *(defaultfilesn[])= {
342                                      "C:\\autoexec.bat",
343                                      "C:\\config.sys",
344                                      "C:\\WINDOWS/System32/eventcreate.exe",
345                                      "C:\\WINDOWS/System32/eventtriggers.exe",
346                                      "C:\\WINDOWS/System32/tlntsvr.exe",
347                                      "C:\\WINDOWS/System32/Tasks",
348                                      NULL
349                                      };
350         while(defaultfilesn[di] != NULL)
351         {
352             if(strcmp(defaultfilesn[di], dir_name) == 0)
353             {
354                 break;
355             }
356             di++;
357         }
358
359         if(defaultfilesn[di] == NULL)
360         {
361             merror("%s: WARN: Error opening directory: '%s': %s ",
362                     ARGV0, dir_name, strerror(errno)); 
363         }
364             
365         #else
366             
367         merror("%s: WARN: Error opening directory: '%s': %s ",
368                                           ARGV0,
369                                           dir_name,
370                                           strerror(errno));
371         #endif
372         
373         return(-1);
374     }
375     
376
377     /* Checking for real time flag. */
378     if(opts & CHECK_REALTIME)
379     {
380         #ifdef USEINOTIFY
381         realtime_adddir(dir_name);
382         #endif
383     }
384
385
386     while((entry = readdir(dp)) != NULL)
387     {
388         char *s_name;
389         
390         /* Just ignore . and ..  */
391         if((strcmp(entry->d_name,".") == 0) ||
392            (strcmp(entry->d_name,"..") == 0))  
393             continue;
394             
395         strncpy(f_name, dir_name, PATH_MAX);
396        
397         s_name = f_name;
398         
399         s_name += dir_size;
400
401
402         /* checking if the file name is already null terminated */
403         if(*(s_name-1) != '/')
404             *s_name++ = '/';
405             
406         *s_name = '\0';
407         
408         strncpy(s_name, entry->d_name, PATH_MAX - dir_size -2);
409         read_file(f_name, opts, restriction);
410     }
411
412     closedir(dp);
413     return(0);
414 }
415
416
417 /* int run_dbcheck */
418 int run_dbcheck()
419 {
420     int i = 0;
421
422     __counter = 0;
423     do
424     {
425         read_dir(syscheck.dir[i], syscheck.opts[i], syscheck.filerestrict[i]);
426         i++;
427     }while(syscheck.dir[i] != NULL);
428
429     return(0);
430 }
431
432
433 /* int create_db
434  * Creates the file database.
435  */
436 int create_db()
437 {
438     int i = 0;
439
440     /* Creating store data */
441     syscheck.fp = OSHash_Create();
442     if(!syscheck.fp)
443     {
444         ErrorExit("%s: Unable to create syscheck database."
445                   ". Exiting.",ARGV0);
446         return(0);    
447     }
448
449     if(!OSHash_setSize(syscheck.fp, 2048))
450     {
451         merror(LIST_ERROR, ARGV0);
452         return(0);
453     }
454
455     
456     /* dir_name can't be null */
457     if((syscheck.dir == NULL) || (syscheck.dir[0] == NULL))
458     {
459         merror("%s: No directories to check.",ARGV0);
460         return(-1);
461     }
462     
463
464     merror("%s: INFO: Starting syscheck database (pre-scan).", ARGV0);
465
466
467     /* Read all available directories */
468     __counter = 0;
469     do
470     {
471         if(read_dir(syscheck.dir[i], syscheck.opts[i], syscheck.filerestrict[i]) == 0)
472         {
473             #ifdef WIN32
474             if(syscheck.opts[i] & CHECK_REALTIME)
475             {
476                 realtime_adddir(syscheck.dir[i]);
477             }
478             #endif
479         }
480         i++;
481     }while(syscheck.dir[i] != NULL);
482
483     
484     merror("%s: INFO: Finished creating syscheck database (pre-scan "
485            "completed).", ARGV0);
486     return(0);
487
488 }
489
490 /* EOF */