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