1 /* Copyright (C) 2009 Trend Micro Inc.
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
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"
21 static int read_file(const char *dir_name, int opts, OSMatch *restriction) __attribute__((nonnull(1)));
23 /* Global variables */
24 static int __counter = 0;
27 /* Read and generate the integrity data of a file */
28 static int read_file(const char *file_name, int opts, OSMatch *restriction)
34 /* Check if the file should be ignored */
35 if (syscheck.ignore) {
37 while (syscheck.ignore[i] != NULL) {
38 if (strncasecmp(syscheck.ignore[i], file_name,
39 strlen(syscheck.ignore[i])) == 0) {
46 /* Check in the regex entry */
47 if (syscheck.ignore_regex) {
49 while (syscheck.ignore_regex[i] != NULL) {
50 if (OSMatch_Execute(file_name, strlen(file_name),
51 syscheck.ignore_regex[i])) {
59 /* Win32 does not have lstat */
60 if (stat(file_name, &statbuf) < 0)
62 if (lstat(file_name, &statbuf) < 0)
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);
73 merror("%s: Error accessing '%s'.", ARGV0, file_name);
78 if (S_ISDIR(statbuf.st_mode)) {
80 verbose("%s: Reading dir: %s\n", ARGV0, file_name);
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);
90 return (read_dir(file_name, opts, restriction));
93 /* Restrict file types */
95 if (!OSMatch_Execute(file_name, strlen(file_name),
101 /* No S_ISLNK on Windows */
103 if (S_ISREG(statbuf.st_mode))
105 if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode))
114 strncpy(mf_sum, "xxx", 4);
115 strncpy(sf_sum, "xxx", 4);
116 strncpy(sf_sum2, "xxx", 4);
117 strncpy(sf_sum3, "xxx", 4);
119 /* Generate checksums */
120 if ((opts & CHECK_MD5SUM) || (opts & CHECK_SHA1SUM)) {
121 /* If it is a link, check if dest is valid */
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);
133 } else if (OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum, OS_BINARY) < 0)
135 if (OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum, OS_BINARY) < 0)
138 strncpy(mf_sum, "xxx", 4);
139 strncpy(sf_sum, "xxx", 4);
142 if (opts & CHECK_SEECHANGES) {
146 if (opts & CHECK_SEECHANGES) {
153 buf = (char *) OSHash_Get(syscheck.fp, file_name);
155 char alert_msg[916 + 1]; /* to accommodate a long */
156 alert_msg[916] = '\0';
159 if (opts & CHECK_SEECHANGES) {
160 char *alertdump = seechanges_addfile(file_name);
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 ? '+' : '-',
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");
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);
186 /* Send the new checksum to the analysis server */
187 alert_msg[916] = '\0';
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",
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);
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();
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);
224 ConvertSidToStringSid(pSidOwner, &szSID);
227 st_uid = (char *) calloc(strlen(szSID) + 1, 1);
228 memcpy(st_uid, szSID, strlen(szSID));
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",
243 send_syscheck_msg(alert_msg);
245 char alert_msg[OS_MAXSTR + 1];
251 alert_msg[OS_MAXSTR] = '\0';
253 /* If it returns < 0, we have already alerted */
254 if (c_read_file(file_name, buf, c_sum) < 0) {
258 if (strcmp(c_sum, buf + 6) != 0) {
259 /* Send the new checksum to the analysis server */
260 alert_msg[OS_MAXSTR] = '\0';
262 snprintf(alert_msg, 916, "%s %s", c_sum, file_name);
264 char *fullalert = NULL;
265 if (buf[5] == 's' || buf[5] == 'n') {
266 fullalert = seechanges_addfile(file_name);
268 snprintf(alert_msg, OS_MAXSTR, "%s %s\n%s", c_sum, file_name, fullalert);
272 snprintf(alert_msg, 916, "%s %s", c_sum, file_name);
275 snprintf(alert_msg, 916, "%s %s", c_sum, file_name);
278 send_syscheck_msg(alert_msg);
283 if (__counter >= (syscheck.sleep_after)) {
284 sleep(syscheck.tsleep);
290 verbose("%s: file '%s %s'", ARGV0, file_name, mf_sum);
294 verbose("%s: *** IRREG file: '%s'\n", ARGV0, file_name);
301 int read_dir(const char *dir_name, int opts, OSMatch *restriction)
304 char f_name[PATH_MAX + 2];
308 struct dirent *entry;
310 f_name[PATH_MAX + 1] = '\0';
312 /* Directory should be valid */
313 if ((dir_size = strlen(dir_name)) > PATH_MAX) {
314 merror(NULL_ERROR, ARGV0);
318 /* Should we check for NFS? */
319 if(syscheck.skip_nfs)
321 is_nfs = IsNFS(dir_name);
324 // Error will be -1, and 1 means skipped
330 /* Open the directory given */
331 dp = opendir(dir_name);
333 if (errno == ENOTDIR) {
334 if (read_file(dir_name, opts, restriction) == 0) {
341 char *(defaultfilesn[]) = {
344 "C:\\WINDOWS/System32/eventcreate.exe",
345 "C:\\WINDOWS/System32/eventtriggers.exe",
346 "C:\\WINDOWS/System32/tlntsvr.exe",
347 "C:\\WINDOWS/System32/Tasks",
350 while (defaultfilesn[di] != NULL) {
351 if (strcmp(defaultfilesn[di], dir_name) == 0) {
357 if (defaultfilesn[di] == NULL) {
358 merror("%s: WARN: Error opening directory: '%s': %s ",
359 ARGV0, dir_name, strerror(errno));
362 merror("%s: WARN: Error opening directory: '%s': %s ",
370 /* Check for real time flag */
371 if (opts & CHECK_REALTIME) {
372 #if defined(INOTIFY_ENABLED) || defined(WIN32)
373 realtime_adddir(dir_name);
375 merror("%s: WARN: realtime monitoring request on unsupported system for '%s'",
382 while ((entry = readdir(dp)) != NULL) {
385 /* Ignore . and .. */
386 if ((strcmp(entry->d_name, ".") == 0) ||
387 (strcmp(entry->d_name, "..") == 0)) {
391 strncpy(f_name, dir_name, PATH_MAX);
395 /* Check if the file name is already null terminated */
396 if (*(s_name - 1) != '/') {
401 strncpy(s_name, entry->d_name, PATH_MAX - dir_size - 2);
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));
409 switch (recurse_sb.st_mode & S_IFMT) {
418 /* Check integrity of the file */
419 read_file(f_name, opts, restriction);
431 while (syscheck.dir[i] != NULL) {
432 read_dir(syscheck.dir[i], syscheck.opts[i], syscheck.filerestrict[i]);
443 /* Create store data */
444 syscheck.fp = OSHash_Create();
446 ErrorExit("%s: Unable to create syscheck database."
447 ". Exiting.", ARGV0);
450 if (!OSHash_setSize(syscheck.fp, 2048)) {
451 merror(LIST_ERROR, ARGV0);
455 if ((syscheck.dir == NULL) || (syscheck.dir[0] == NULL)) {
456 merror("%s: No directories to check.", ARGV0);
460 merror("%s: INFO: Starting syscheck database (pre-scan).", ARGV0);
462 /* Read all available directories */
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]);
469 } while (syscheck.dir[i] != NULL);
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);
476 merror("%s: INFO: Finished creating syscheck database (pre-scan "
477 "completed).", ARGV0);