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