1 /* @(#) $Id: ./src/rootcheck/common.c, 2011/09/08 dcid Exp $
4 /* Copyright (C) 2009 Trend Micro Inc.
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
12 * License details at the LICENSE file included with OSSEC or
13 * online at: http://www.ossec.net/main/license/ .
18 #include "rootcheck.h"
19 #include "os_regex/os_regex.h"
23 /** Checks if the specified string is already in the array.
25 int _is_str_in_array(char **ar, char *str)
29 if(strcmp(*ar, str) == 0)
40 /** int rk_check_dir(char *dir, char *file, char *pattern)
42 int rk_check_dir(char *dir, char *file, char *pattern)
45 char f_name[PATH_MAX +2];
47 struct stat statbuf_local;
51 f_name[PATH_MAX +1] = '\0';
59 while((entry = readdir(dp)) != NULL)
61 /* Just ignore . and .. */
62 if((strcmp(entry->d_name,".") == 0) ||
63 (strcmp(entry->d_name,"..") == 0))
69 /* Creating new file + path string */
70 snprintf(f_name, PATH_MAX +1, "%s/%s",dir, entry->d_name);
73 /* Checking if the read entry, matches the provided file name. */
74 if(strncasecmp(file, "r:", 2) == 0)
76 if(OS_Regex(file +2, entry->d_name))
78 if(rk_check_file(f_name, pattern))
85 /* Trying without regex. */
88 if(OS_Match2(file, entry->d_name))
90 if(rk_check_file(f_name, pattern))
98 /* Checking if file is a directory */
99 if(lstat(f_name, &statbuf_local) == 0)
101 if(S_ISDIR(statbuf_local.st_mode))
103 if(rk_check_dir(f_name, file, pattern))
118 /** int rk_check_file(char *value, char *pattern)
120 int rk_check_file(char *file, char *pattern)
127 char buf[OS_SIZE_2048 +1];
130 /* If string is null, we don't match */
137 /* Checking if the file is divided */
138 split_file = strchr(file, ',');
146 /* Getting each file */
151 /* If we don't have a pattern, just check if the file/dir is there */
157 char _b_msg[OS_SIZE_1024 +1];
159 _b_msg[OS_SIZE_1024] = '\0';
160 snprintf(_b_msg, OS_SIZE_1024, " File: %s.",
163 /* Already present. */
164 if(_is_str_in_array(rootcheck.alert_msg, _b_msg))
169 while(rootcheck.alert_msg[i] && (i < 255))
172 if(!rootcheck.alert_msg[i])
173 os_strdup(_b_msg, rootcheck.alert_msg[i]);
181 full_negate = pt_check_negate(pattern);
182 /* Checking for a content in the file */
183 debug1("checking file: %s", file);
184 fp = fopen(file, "r");
188 debug1(" starting new file: %s", file);
189 buf[OS_SIZE_2048] = '\0';
190 while(fgets(buf, OS_SIZE_2048, fp) != NULL)
194 /* Removing end of line */
195 nbuf = strchr(buf, '\n');
203 /* Removing end of line */
204 nbuf = strchr(buf, '\r');
213 pt_result = pt_matches(buf, pattern);
214 debug1("Buf == \"%s\"", buf);
215 debug1("Pattern == \"%s\"", pattern);
216 debug1("pt_result == %d and full_negate == %d", pt_result, full_negate);
217 if((pt_result == 1 && full_negate == 0) )
219 debug1("alerting file %s on line %s", file, buf);
221 char _b_msg[OS_SIZE_1024 +1];
224 /* Closing the file before dealing with the alert. */
227 /* Generating the alert itself. */
228 _b_msg[OS_SIZE_1024] = '\0';
229 snprintf(_b_msg, OS_SIZE_1024, " File: %s.",
232 /* Already present. */
233 if(_is_str_in_array(rootcheck.alert_msg, _b_msg))
238 while(rootcheck.alert_msg[i] && (i < 255))
241 if(!rootcheck.alert_msg[i])
242 os_strdup(_b_msg, rootcheck.alert_msg[i]);
246 else if((pt_result == 0 && full_negate == 1) )
248 /* found a full+negate match so no longer need to search
249 * break out of loop and amke sure the full negate does
252 debug1("found a complete match for full_negate");
262 debug1("full_negate alerting - file %s",file);
264 char _b_msg[OS_SIZE_1024 +1];
266 /* Generating the alert itself. */
267 _b_msg[OS_SIZE_1024] = '\0';
268 snprintf(_b_msg, OS_SIZE_1024, " File: %s.",
271 /* Already present. */
272 if(_is_str_in_array(rootcheck.alert_msg, _b_msg))
277 while(rootcheck.alert_msg[i] && (i < 255))
280 if(!rootcheck.alert_msg[i])
281 os_strdup(_b_msg, rootcheck.alert_msg[i]);
291 split_file = strchr(split_file, ',');
306 /** int pt_check_negate(char *pattern)
307 * Checks if the patterns is all negate values and if so returns 1
310 int pt_check_negate(char *pattern)
312 char *mypattern = NULL;
313 os_strdup(pattern, mypattern);
314 char *tmp_pt = mypattern;
315 char *tmp_pattern = mypattern;
316 char *tmp_ret = NULL;
319 while(tmp_pt != NULL)
321 /* We first look for " && " */
322 tmp_pt = strchr(tmp_pattern, ' ');
323 if(tmp_pt && tmp_pt[1] == '&' && tmp_pt[2] == '&' && tmp_pt[3] == ' ')
325 /* Marking pointer to clean it up */
336 if(*tmp_pattern != '!')
342 tmp_pattern = tmp_pt;
345 debug1("pattern: %s is fill_negate",pattern);
350 /** int pt_matches(char *str, char *pattern)
351 * Checks if the specific pattern is present on str.
352 * A pattern can be preceeded by:
353 * =: (for equal) - default - strcasecmp
354 * r: (for ossec regexes)
355 * >: (for strcmp greater)
356 * <: (for strcmp lower)
358 * Multiple patterns can be specified by using " && " between them.
359 * All of them must match for it to return true.
361 int pt_matches(char *str, char *pattern)
365 char *tmp_pt = pattern;
366 char *tmp_ret = NULL;
369 /* If string we null, we don't match */
375 while(tmp_pt != NULL)
377 /* We first look for " && " */
378 tmp_pt = strchr(pattern, ' ');
379 if(tmp_pt && tmp_pt[1] == '&' && tmp_pt[2] == '&' && tmp_pt[3] == ' ')
381 /* Marking pointer to clean it up */
393 /* Checking for negate values */
403 /* Doing strcasecmp */
404 if(strncasecmp(pattern, "=:", 2) == 0)
407 if(strcasecmp(pattern, str) == 0)
412 else if(strncasecmp(pattern, "r:", 2) == 0)
415 if(OS_Regex(pattern, str))
417 debug1("pattern: %s matches %s.",pattern, str);
421 else if(strncasecmp(pattern, "<:", 2) == 0)
424 if(strcmp(pattern, str) < 0)
429 else if(strncasecmp(pattern, ">:", 2) == 0)
432 if(strcmp(pattern, str) > 0)
440 char final_file[2048 +1];
442 /* Try to get Windows variable */
445 final_file[0] = '\0';
446 final_file[2048] = '\0';
448 ExpandEnvironmentStrings(pattern, final_file, 2047);
452 strncpy(final_file, pattern, 2047);
455 /* Comparing against the expanded variable */
456 if(strcasecmp(final_file, str) == 0)
462 if(strcasecmp(pattern, str) == 0)
470 /* Fixing tmp_ret entry */
478 /* If we have "!", return true if we don't match */
505 /** char *normalize_string
506 * Normalizes a string, removing white spaces and tabs
507 * from the begining and the end of it.
509 char *normalize_string(char *str)
511 unsigned int str_sz = strlen(str);
512 // return zero-length str as is
518 // remove trailing spaces
519 while(str[str_sz] == ' ' || str[str_sz] == '\t')
524 str[str_sz--] = '\0';
526 // ignore leading spaces
529 if(*str == ' ' || *str == '\t')
546 /** int isfile_ondir(char *file, char *dir)
547 * Checks is 'file' is present on 'dir' using readdir
549 int isfile_ondir(char *file, char *dir)
552 struct dirent *entry;
558 while((entry = readdir(dp)) != NULL)
560 if(strcmp(entry->d_name, file) == 0)
573 /* is_file: Check if the file is present
574 * by different attempts (to try to avoid syscall hidding).
576 int is_file(char *file_name)
593 curr_dir[1023] = '\0';
595 if(!getcwd(curr_dir, 1022))
600 /* Getting dir name */
601 file_basename = strrchr(file_name, '/');
604 merror("%s: RK: Invalid file name: %s!", ARGV0, file_name);
609 /* If file_basename == file_name, then the file
610 * only has one slash at the beginning.
612 if(file_basename != file_name)
614 /* Dir name and base name are now set */
615 *file_basename = '\0';
617 file_dirname = file_name;
620 if(chdir(file_dirname) == 0)
622 if(chdir(file_basename) == 0)
626 /* Checking errno (if file exists, but it is not
629 else if(errno == ENOTDIR)
634 /** Trying open dir **/
635 dp = opendir(file_basename);
641 else if(errno == ENOTDIR)
646 /* Returning to the previous directory */
652 *file_basename = '/';
657 if(chdir(file_name) == 0)
661 /* Returning to the previous directory */
664 else if(errno == ENOTDIR)
671 dp = opendir(file_name);
681 /* Trying other calls */
682 if( (stat(file_name, &statbuf) < 0) &&
684 (access(file_name, F_OK) < 0) &&
686 ((fp = fopen(file_name, "r")) == NULL))
691 /* must close it over here */
700 /* del_plist:. Deletes the process list
702 int del_plist(void *p_list_p)
704 OSList *p_list = (OSList *)p_list_p;
706 OSListNode *p_node = NULL;
713 l_node = OSList_GetFirstNode(p_list);
718 pinfo = (Proc_Info *)l_node->data;
739 l_node = OSList_GetNextNode(p_list);
755 /* is_process: Check is a process is running.
757 int is_process(char *value, void *p_list_p)
759 OSList *p_list = (OSList *)p_list_p;
771 l_node = OSList_GetFirstNode(p_list);
776 pinfo = (Proc_Info *)l_node->data;
778 /* Checking if value matches */
779 if(pt_matches(pinfo->p_path, value))
782 char _b_msg[OS_SIZE_1024 +1];
784 _b_msg[OS_SIZE_1024] = '\0';
786 snprintf(_b_msg, OS_SIZE_1024, " Process: %s.",
789 /* Already present. */
790 if(_is_str_in_array(rootcheck.alert_msg, _b_msg))
795 while(rootcheck.alert_msg[i] && (i< 255))
798 if(!rootcheck.alert_msg[i])
799 os_strdup(_b_msg, rootcheck.alert_msg[i]);
804 l_node = OSList_GetNextNode(p_list);