4c0b6ba75970dcce9f595b1a9aa9145697ffaf85
[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         #ifdef WIN32
110         /* Directory links are not supported */
111         if (GetFileAttributes(file_name) & FILE_ATTRIBUTE_REPARSE_POINT) {
112             merror("%s: WARN: Links are not supported: '%s'", ARGV0, file_name);
113             return(-1);
114         }
115         #endif
116         return(read_dir(file_name, opts, restriction));
117     }
118
119
120     /* restricting file types. */
121     if(restriction)
122     {
123         if(!OSMatch_Execute(file_name, strlen(file_name),
124                             restriction))
125         {
126             return(0);
127         }
128     }
129
130
131     /* No S_ISLNK on windows */
132     #ifdef WIN32
133     if(S_ISREG(statbuf.st_mode))
134     #else
135     if(S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode))
136     #endif
137     {
138         os_md5 mf_sum;
139         os_sha1 sf_sum;
140         os_sha1 sf_sum2;
141         os_sha1 sf_sum3;
142
143
144         /* Cleaning sums */
145         strncpy(mf_sum, "xxx", 4);
146         strncpy(sf_sum, "xxx", 4);
147         strncpy(sf_sum2, "xxx", 4);
148         strncpy(sf_sum3, "xxx", 4);
149
150
151         /* Generating checksums. */
152         if((opts & CHECK_MD5SUM) || (opts & CHECK_SHA1SUM))
153         {
154             /* If it is a link, we need to check if dest is valid. */
155             #ifndef WIN32
156             if(S_ISLNK(statbuf.st_mode))
157             {
158                 struct stat statbuf_lnk;
159                 if(stat(file_name, &statbuf_lnk) == 0)
160                 {
161                     if(S_ISREG(statbuf_lnk.st_mode))
162                     {
163                         if(OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum) < 0)
164                         {
165                             strncpy(mf_sum, "xxx", 4);
166                             strncpy(sf_sum, "xxx", 4);
167                         }
168                     }
169                 }
170             }
171             else if(OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum) < 0)
172
173             #else
174             if(OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum) < 0)
175             #endif
176
177             {
178                 strncpy(mf_sum, "xxx", 4);
179                 strncpy(sf_sum, "xxx", 4);
180
181             }
182
183             if(opts & CHECK_SEECHANGES)
184             {
185                 sha1s = 's';
186             }
187         }
188         else
189         {
190             if(opts & CHECK_SEECHANGES)
191                 sha1s = 'n';
192             else
193                 sha1s = '-';
194         }
195
196
197         buf = OSHash_Get(syscheck.fp, file_name);
198         if(!buf)
199         {
200             char alert_msg[916 +1];     /* 912 -> 916 to accommodate a long */
201
202             alert_msg[916] = '\0';
203
204             #ifndef WIN32
205             if(opts & CHECK_SEECHANGES)
206             {
207                 char *alertdump = seechanges_addfile(file_name);
208                 if(alertdump)
209                 {
210                     free(alertdump);
211                     alertdump = NULL;
212                 }
213             }
214             #endif
215
216
217             snprintf(alert_msg, 916, "%c%c%c%c%c%c%ld:%d:%d:%d:%s:%s",
218                 opts & CHECK_SIZE?'+':'-',
219                 opts & CHECK_PERM?'+':'-',
220                 opts & CHECK_OWNER?'+':'-',
221                 opts & CHECK_GROUP?'+':'-',
222                 opts & CHECK_MD5SUM?'+':'-',
223                 sha1s,
224                 opts & CHECK_SIZE?(long)statbuf.st_size:0,
225                 opts & CHECK_PERM?(int)statbuf.st_mode:0,
226                 opts & CHECK_OWNER?(int)statbuf.st_uid:0,
227                 opts & CHECK_GROUP?(int)statbuf.st_gid:0,
228                 opts & CHECK_MD5SUM?mf_sum:"xxx",
229                 opts & CHECK_SHA1SUM?sf_sum:"xxx");
230
231             if(OSHash_Add(syscheck.fp, strdup(file_name), strdup(alert_msg)) <= 0)
232             {
233                 merror("%s: ERROR: Unable to add file to db: %s", ARGV0, file_name);
234             }
235
236
237             /* Sending the new checksum to the analysis server */
238             alert_msg[916] = '\0';
239
240             /* changed by chris st_size int to long, 912 to 916*/
241             snprintf(alert_msg, 916, "%ld:%d:%d:%d:%s:%s %s",
242                      opts & CHECK_SIZE?(long)statbuf.st_size:0,
243                      opts & CHECK_PERM?(int)statbuf.st_mode:0,
244                      opts & CHECK_OWNER?(int)statbuf.st_uid:0,
245                      opts & CHECK_GROUP?(int)statbuf.st_gid:0,
246                      opts & CHECK_MD5SUM?mf_sum:"xxx",
247                      opts & CHECK_SHA1SUM?sf_sum:"xxx",
248                      file_name);
249             send_syscheck_msg(alert_msg);
250         }
251         else
252         {
253             char alert_msg[OS_MAXSTR +1];
254             char c_sum[256 +2];
255
256             c_sum[0] = '\0';
257             c_sum[256] = '\0';
258             alert_msg[0] = '\0';
259             alert_msg[OS_MAXSTR] = '\0';
260
261             /* If it returns < 0, we will already have alerted. */
262             if(c_read_file(file_name, buf, c_sum) < 0)
263                 return(0);
264
265             if(strcmp(c_sum, buf+6) != 0)
266             {
267                 /* Sending the new checksum to the analysis server */
268                 alert_msg[OS_MAXSTR] = '\0';
269                 #ifdef WIN32
270                 snprintf(alert_msg, 916, "%s %s", c_sum, file_name);
271                 #else
272                 char *fullalert = NULL;
273                 if(buf[5] == 's' || buf[5] == 'n')
274                 {
275                     fullalert = seechanges_addfile(file_name);
276                     if(fullalert)
277                     {
278                         snprintf(alert_msg, OS_MAXSTR, "%s %s\n%s", c_sum, file_name, fullalert);
279                         free(fullalert);
280                         fullalert = NULL;
281                     }
282                     else
283                     {
284                         snprintf(alert_msg, 916, "%s %s", c_sum, file_name);
285                     }
286                 }
287                 else
288                 {
289                     snprintf(alert_msg, 916, "%s %s", c_sum, file_name);
290                 }
291                 #endif
292                 send_syscheck_msg(alert_msg);
293             }
294         }
295
296
297         /* Sleeping in here too */
298         if(__counter >= (syscheck.sleep_after))
299         {
300             sleep(syscheck.tsleep);
301             __counter = 0;
302         }
303         __counter++;
304
305
306         #ifdef DEBUG
307         verbose("%s: file '%s %s'",ARGV0, file_name, mf_sum);
308         #endif
309     }
310     else
311     {
312         #ifdef DEBUG
313         verbose("%s: *** IRREG file: '%s'\n",ARGV0,file_name);
314         #endif
315     }
316
317     return(0);
318 }
319
320
321 /* read_dir v0.1
322  *
323  */
324 int read_dir(char *dir_name, int opts, OSMatch *restriction)
325 {
326     int dir_size;
327
328     char f_name[PATH_MAX +2];
329     DIR *dp;
330
331     struct dirent *entry;
332
333     f_name[PATH_MAX +1] = '\0';
334
335
336     /* Directory should be valid */
337     if((dir_name == NULL)||((dir_size = strlen(dir_name)) > PATH_MAX))
338     {
339         merror(NULL_ERROR, ARGV0);
340
341         return(-1);
342     }
343
344
345     /* Opening the directory given */
346     dp = opendir(dir_name);
347     if(!dp)
348     {
349         if(errno == ENOTDIR)
350         {
351             if(read_file(dir_name, opts, restriction) == 0)
352                 return(0);
353         }
354
355         #ifdef WIN32
356         int di = 0;
357         char *(defaultfilesn[])= {
358                                      "C:\\autoexec.bat",
359                                      "C:\\config.sys",
360                                      "C:\\WINDOWS/System32/eventcreate.exe",
361                                      "C:\\WINDOWS/System32/eventtriggers.exe",
362                                      "C:\\WINDOWS/System32/tlntsvr.exe",
363                                      "C:\\WINDOWS/System32/Tasks",
364                                      NULL
365                                      };
366         while(defaultfilesn[di] != NULL)
367         {
368             if(strcmp(defaultfilesn[di], dir_name) == 0)
369             {
370                 break;
371             }
372             di++;
373         }
374
375         if(defaultfilesn[di] == NULL)
376         {
377             merror("%s: WARN: Error opening directory: '%s': %s ",
378                     ARGV0, dir_name, strerror(errno));
379         }
380
381         #else
382
383         merror("%s: WARN: Error opening directory: '%s': %s ",
384                                           ARGV0,
385                                           dir_name,
386                                           strerror(errno));
387         #endif
388
389         return(-1);
390     }
391
392
393     /* Checking for real time flag. */
394     if(opts & CHECK_REALTIME)
395     {
396         #ifdef USEINOTIFY
397         realtime_adddir(dir_name);
398         #endif
399     }
400
401
402     while((entry = readdir(dp)) != NULL)
403     {
404         char *s_name;
405
406         /* Just ignore . and ..  */
407         if((strcmp(entry->d_name,".") == 0) ||
408            (strcmp(entry->d_name,"..") == 0))
409             continue;
410
411         strncpy(f_name, dir_name, PATH_MAX);
412
413         s_name = f_name;
414
415         s_name += dir_size;
416
417
418         /* checking if the file name is already null terminated */
419         if(*(s_name-1) != '/')
420             *s_name++ = '/';
421
422         *s_name = '\0';
423
424         strncpy(s_name, entry->d_name, PATH_MAX - dir_size -2);
425
426         /* Check integrity of the file */
427         read_file(f_name, opts, restriction);
428     }
429
430     closedir(dp);
431     return(0);
432 }
433
434
435 /* int run_dbcheck */
436 int run_dbcheck()
437 {
438     int i = 0;
439
440     __counter = 0;
441     while(syscheck.dir[i] != NULL)
442     {
443         read_dir(syscheck.dir[i], syscheck.opts[i], syscheck.filerestrict[i]);
444         i++;
445     }
446
447     return(0);
448 }
449
450
451 /* int create_db
452  * Creates the file database.
453  */
454 int create_db()
455 {
456     int i = 0;
457
458     /* Creating store data */
459     syscheck.fp = OSHash_Create();
460     if(!syscheck.fp)
461     {
462         ErrorExit("%s: Unable to create syscheck database."
463                   ". Exiting.",ARGV0);
464         return(0);
465     }
466
467     if(!OSHash_setSize(syscheck.fp, 2048))
468     {
469         merror(LIST_ERROR, ARGV0);
470         return(0);
471     }
472
473
474     /* dir_name can't be null */
475     if((syscheck.dir == NULL) || (syscheck.dir[0] == NULL))
476     {
477         merror("%s: No directories to check.",ARGV0);
478         return(-1);
479     }
480
481
482     merror("%s: INFO: Starting syscheck database (pre-scan).", ARGV0);
483
484
485     /* Read all available directories */
486     __counter = 0;
487     do
488     {
489         if(read_dir(syscheck.dir[i], syscheck.opts[i], syscheck.filerestrict[i]) == 0)
490         {
491             #ifdef WIN32
492             if(syscheck.opts[i] & CHECK_REALTIME)
493             {
494                 realtime_adddir(syscheck.dir[i]);
495             }
496             #endif
497         }
498         i++;
499     }while(syscheck.dir[i] != NULL);
500
501     #if defined (USEINOTIFY) || defined (WIN32)
502     if(syscheck.realtime && (syscheck.realtime->fd >= 0))
503         verbose("%s: INFO: Real time file monitoring started.", ARGV0);
504     #endif
505
506     merror("%s: INFO: Finished creating syscheck database (pre-scan "
507            "completed).", ARGV0);
508     return(0);
509
510 }
511
512 /* EOF */