3 /* Copyright (C) 2009 Trend Micro Inc.
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 2) as published by the FSF - Free Software
11 * License details at the LICENSE file included with OSSEC or
12 * online at: http://www.ossec.net/main/license/ .
17 #include "rootcheck.h"
18 #include "os_regex/os_regex.h"
22 /** Checks if the specified string is already in the array.
24 int _is_str_in_array(char **ar, char *str)
28 if(strcmp(*ar, str) == 0)
39 /** int rk_check_dir(char *dir, char *file, char *pattern)
41 int rk_check_dir(char *dir, char *file, char *pattern)
44 char f_name[PATH_MAX +2];
46 struct stat statbuf_local;
50 f_name[PATH_MAX +1] = '\0';
58 while((entry = readdir(dp)) != NULL)
60 /* Just ignore . and .. */
61 if((strcmp(entry->d_name,".") == 0) ||
62 (strcmp(entry->d_name,"..") == 0))
68 /* Creating new file + path string */
69 snprintf(f_name, PATH_MAX +1, "%s/%s",dir, entry->d_name);
72 /* Checking if the read entry, matches the provided file name. */
73 if(strncasecmp(file, "r:", 2) == 0)
75 if(OS_Regex(file +2, entry->d_name))
77 if(rk_check_file(f_name, pattern))
84 /* Trying without regex. */
87 if(OS_Match2(file, entry->d_name))
89 if(rk_check_file(f_name, pattern))
97 /* Checking if file is a directory */
98 if(lstat(f_name, &statbuf_local) == 0)
100 if(S_ISDIR(statbuf_local.st_mode))
102 if(rk_check_dir(f_name, file, pattern))
117 /** int rk_check_file(char *value, char *pattern)
119 int rk_check_file(char *file, char *pattern)
126 char buf[OS_SIZE_2048 +1];
129 /* If string is null, we don't match */
136 /* Checking if the file is divided */
137 split_file = strchr(file, ',');
145 /* Getting each file */
150 /* If we don't have a pattern, just check if the file/dir is there */
156 char _b_msg[OS_SIZE_1024 +1];
158 _b_msg[OS_SIZE_1024] = '\0';
159 snprintf(_b_msg, OS_SIZE_1024, " File: %s.",
162 /* Already present. */
163 if(_is_str_in_array(rootcheck.alert_msg, _b_msg))
168 while(rootcheck.alert_msg[i] && (i < 255))
171 if(!rootcheck.alert_msg[i])
172 os_strdup(_b_msg, rootcheck.alert_msg[i]);
180 full_negate = pt_check_negate(pattern);
181 /* Checking for a content in the file */
182 debug1("checking file: %s", file);
183 fp = fopen(file, "r");
187 debug1(" starting new file: %s", file);
188 buf[OS_SIZE_2048] = '\0';
189 while(fgets(buf, OS_SIZE_2048, fp) != NULL)
193 /* Removing end of line */
194 nbuf = strchr(buf, '\n');
202 /* Removing end of line */
203 nbuf = strchr(buf, '\r');
212 pt_result = pt_matches(buf, pattern);
213 debug1("Buf == \"%s\"", buf);
214 debug1("Pattern == \"%s\"", pattern);
215 debug1("pt_result == %d and full_negate == %d", pt_result, full_negate);
216 if((pt_result == 1 && full_negate == 0) )
218 debug1("alerting file %s on line %s", file, buf);
220 char _b_msg[OS_SIZE_1024 +1];
223 /* Closing the file before dealing with the alert. */
226 /* Generating the alert itself. */
227 _b_msg[OS_SIZE_1024] = '\0';
228 snprintf(_b_msg, OS_SIZE_1024, " File: %s.",
231 /* Already present. */
232 if(_is_str_in_array(rootcheck.alert_msg, _b_msg))
237 while(rootcheck.alert_msg[i] && (i < 255))
240 if(!rootcheck.alert_msg[i])
241 os_strdup(_b_msg, rootcheck.alert_msg[i]);
245 else if((pt_result == 0 && full_negate == 1) )
247 /* found a full+negate match so no longer need to search
248 * break out of loop and amke sure the full negate does
251 debug1("found a complete match for full_negate");
261 debug1("full_negate alerting - file %s",file);
263 char _b_msg[OS_SIZE_1024 +1];
265 /* Generating the alert itself. */
266 _b_msg[OS_SIZE_1024] = '\0';
267 snprintf(_b_msg, OS_SIZE_1024, " File: %s.",
270 /* Already present. */
271 if(_is_str_in_array(rootcheck.alert_msg, _b_msg))
276 while(rootcheck.alert_msg[i] && (i < 255))
279 if(!rootcheck.alert_msg[i])
280 os_strdup(_b_msg, rootcheck.alert_msg[i]);
290 split_file = strchr(split_file, ',');
305 /** int pt_check_negate(char *pattern)
306 * Checks if the patterns is all negate values and if so returns 1
309 int pt_check_negate(char *pattern)
311 char *mypattern = NULL;
312 os_strdup(pattern, mypattern);
313 char *tmp_pt = mypattern;
314 char *tmp_pattern = mypattern;
315 char *tmp_ret = NULL;
318 while(tmp_pt != NULL)
320 /* We first look for " && " */
321 tmp_pt = strchr(tmp_pattern, ' ');
322 if(tmp_pt && tmp_pt[1] == '&' && tmp_pt[2] == '&' && tmp_pt[3] == ' ')
324 /* Marking pointer to clean it up */
335 if(*tmp_pattern != '!')
341 tmp_pattern = tmp_pt;
344 debug1("pattern: %s is fill_negate",pattern);
349 /** int pt_matches(char *str, char *pattern)
350 * Checks if the specific pattern is present on str.
351 * A pattern can be preceeded by:
352 * =: (for equal) - default - strcasecmp
353 * r: (for ossec regexes)
354 * >: (for strcmp greater)
355 * <: (for strcmp lower)
357 * Multiple patterns can be specified by using " && " between them.
358 * All of them must match for it to return true.
360 int pt_matches(char *str, char *pattern)
364 char *tmp_pt = pattern;
365 char *tmp_ret = NULL;
368 /* If string we null, we don't match */
374 while(tmp_pt != NULL)
376 /* We first look for " && " */
377 tmp_pt = strchr(pattern, ' ');
378 if(tmp_pt && tmp_pt[1] == '&' && tmp_pt[2] == '&' && tmp_pt[3] == ' ')
380 /* Marking pointer to clean it up */
392 /* Checking for negate values */
402 /* Doing strcasecmp */
403 if(strncasecmp(pattern, "=:", 2) == 0)
406 if(strcasecmp(pattern, str) == 0)
411 else if(strncasecmp(pattern, "r:", 2) == 0)
414 if(OS_Regex(pattern, str))
416 debug1("pattern: %s matches %s.",pattern, str);
420 else if(strncasecmp(pattern, "<:", 2) == 0)
423 if(strcmp(pattern, str) < 0)
428 else if(strncasecmp(pattern, ">:", 2) == 0)
431 if(strcmp(pattern, str) > 0)
439 char final_file[2048 +1];
441 /* Try to get Windows variable */
444 final_file[0] = '\0';
445 final_file[2048] = '\0';
447 ExpandEnvironmentStrings(pattern, final_file, 2047);
451 strncpy(final_file, pattern, 2047);
454 /* Comparing against the expanded variable */
455 if(strcasecmp(final_file, str) == 0)
461 if(strcasecmp(pattern, str) == 0)
469 /* Fixing tmp_ret entry */
477 /* If we have "!", return true if we don't match */
504 /** char *normalize_string
505 * Normalizes a string, removing white spaces and tabs
506 * from the begining and the end of it.
508 char *normalize_string(char *str)
510 int str_sz = strlen(str) -1;
514 if(*str == ' ' || *str == '\t')
524 while(str[str_sz] == ' ' || str[str_sz] == '\t')
535 /** int isfile_ondir(char *file, char *dir)
536 * Checks is 'file' is present on 'dir' using readdir
538 int isfile_ondir(char *file, char *dir)
541 struct dirent *entry;
547 while((entry = readdir(dp)) != NULL)
549 if(strcmp(entry->d_name, file) == 0)
562 /* is_file: Check if the file is present
563 * by different attempts (to try to avoid syscall hidding).
565 int is_file(char *file_name)
582 curr_dir[1023] = '\0';
584 if(!getcwd(curr_dir, 1022))
589 /* Getting dir name */
590 file_basename = strrchr(file_name, '/');
593 merror("%s: RK: Invalid file name: %s!", ARGV0, file_name);
598 /* If file_basename == file_name, then the file
599 * only has one slash at the beginning.
601 if(file_basename != file_name)
603 /* Dir name and base name are now set */
604 *file_basename = '\0';
606 file_dirname = file_name;
609 if(chdir(file_dirname) == 0)
611 if(chdir(file_basename) == 0)
615 /* Checking errno (if file exists, but it is not
618 else if(errno == ENOTDIR)
623 /** Trying open dir **/
624 dp = opendir(file_basename);
630 else if(errno == ENOTDIR)
635 /* Returning to the previous directory */
641 *file_basename = '/';
646 if(chdir(file_name) == 0)
650 /* Returning to the previous directory */
653 else if(errno == ENOTDIR)
660 dp = opendir(file_name);
670 /* Trying other calls */
671 if( (stat(file_name, &statbuf) < 0) &&
673 (access(file_name, F_OK) < 0) &&
675 ((fp = fopen(file_name, "r")) == NULL))
680 /* must close it over here */
689 /* del_plist:. Deletes the process list
691 int del_plist(void *p_list_p)
693 OSList *p_list = (OSList *)p_list_p;
695 OSListNode *p_node = NULL;
702 l_node = OSList_GetFirstNode(p_list);
707 pinfo = (Proc_Info *)l_node->data;
728 l_node = OSList_GetNextNode(p_list);
744 /* is_process: Check is a process is running.
746 int is_process(char *value, void *p_list_p)
748 OSList *p_list = (OSList *)p_list_p;
760 l_node = OSList_GetFirstNode(p_list);
765 pinfo = (Proc_Info *)l_node->data;
767 /* Checking if value matches */
768 if(pt_matches(pinfo->p_path, value))
771 char _b_msg[OS_SIZE_1024 +1];
773 _b_msg[OS_SIZE_1024] = '\0';
775 snprintf(_b_msg, OS_SIZE_1024, " Process: %s.",
778 /* Already present. */
779 if(_is_str_in_array(rootcheck.alert_msg, _b_msg))
784 while(rootcheck.alert_msg[i] && (i< 255))
787 if(!rootcheck.alert_msg[i])
788 os_strdup(_b_msg, rootcheck.alert_msg[i]);
793 l_node = OSList_GetNextNode(p_list);