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