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;
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] == ' ')
332 if(*tmp_pattern != '!')
338 tmp_pattern = tmp_pt;
341 debug1("pattern: %s is fill_negate",pattern);
346 /** int pt_matches(char *str, char *pattern)
347 * Checks if the specific pattern is present on str.
348 * A pattern can be preceeded by:
349 * =: (for equal) - default - strcasecmp
350 * r: (for ossec regexes)
351 * >: (for strcmp greater)
352 * <: (for strcmp lower)
354 * Multiple patterns can be specified by using " && " between them.
355 * All of them must match for it to return true.
357 int pt_matches(char *str, char *pattern)
361 char *tmp_pt = pattern;
362 char *tmp_ret = NULL;
365 /* If string we null, we don't match */
371 while(tmp_pt != NULL)
373 /* We first look for " && " */
374 tmp_pt = strchr(pattern, ' ');
375 if(tmp_pt && tmp_pt[1] == '&' && tmp_pt[2] == '&' && tmp_pt[3] == ' ')
377 /* Marking pointer to clean it up */
389 /* Checking for negate values */
399 /* Doing strcasecmp */
400 if(strncasecmp(pattern, "=:", 2) == 0)
403 if(strcasecmp(pattern, str) == 0)
408 else if(strncasecmp(pattern, "r:", 2) == 0)
411 if(OS_Regex(pattern, str))
413 debug1("pattern: %s matches %s.",pattern, str);
417 else if(strncasecmp(pattern, "<:", 2) == 0)
420 if(strcmp(pattern, str) < 0)
425 else if(strncasecmp(pattern, ">:", 2) == 0)
428 if(strcmp(pattern, str) > 0)
436 char final_file[2048 +1];
438 /* Try to get Windows variable */
441 final_file[0] = '\0';
442 final_file[2048] = '\0';
444 ExpandEnvironmentStrings(pattern, final_file, 2047);
448 strncpy(final_file, pattern, 2047);
451 /* Comparing against the expanded variable */
452 if(strcasecmp(final_file, str) == 0)
458 if(strcasecmp(pattern, str) == 0)
466 /* Fixing tmp_ret entry */
474 /* If we have "!", return true if we don't match */
501 /** char *normalize_string
502 * Normalizes a string, removing white spaces and tabs
503 * from the begining and the end of it.
505 char *normalize_string(char *str)
507 unsigned int str_sz = strlen(str);
508 // return zero-length str as is
514 // remove trailing spaces
515 while(str[str_sz] == ' ' || str[str_sz] == '\t')
520 str[str_sz--] = '\0';
522 // ignore leading spaces
525 if(*str == ' ' || *str == '\t')
542 /** int isfile_ondir(char *file, char *dir)
543 * Checks is 'file' is present on 'dir' using readdir
545 int isfile_ondir(char *file, char *dir)
548 struct dirent *entry;
554 while((entry = readdir(dp)) != NULL)
556 if(strcmp(entry->d_name, file) == 0)
569 /* is_file: Check if the file is present
570 * by different attempts (to try to avoid syscall hidding).
572 int is_file(char *file_name)
589 curr_dir[1023] = '\0';
591 if(!getcwd(curr_dir, 1022))
596 /* Getting dir name */
597 file_basename = strrchr(file_name, '/');
600 merror("%s: RK: Invalid file name: %s!", ARGV0, file_name);
605 /* If file_basename == file_name, then the file
606 * only has one slash at the beginning.
608 if(file_basename != file_name)
610 /* Dir name and base name are now set */
611 *file_basename = '\0';
613 file_dirname = file_name;
616 if(chdir(file_dirname) == 0)
618 if(chdir(file_basename) == 0)
622 /* Checking errno (if file exists, but it is not
625 else if(errno == ENOTDIR)
630 /** Trying open dir **/
631 dp = opendir(file_basename);
637 else if(errno == ENOTDIR)
642 /* Returning to the previous directory */
648 *file_basename = '/';
653 if(chdir(file_name) == 0)
657 /* Returning to the previous directory */
660 else if(errno == ENOTDIR)
667 dp = opendir(file_name);
677 /* Trying other calls */
678 if( (stat(file_name, &statbuf) < 0) &&
680 (access(file_name, F_OK) < 0) &&
682 ((fp = fopen(file_name, "r")) == NULL))
687 /* must close it over here */
696 /* del_plist:. Deletes the process list
698 int del_plist(void *p_list_p)
700 OSList *p_list = (OSList *)p_list_p;
702 OSListNode *p_node = NULL;
709 l_node = OSList_GetFirstNode(p_list);
714 pinfo = (Proc_Info *)l_node->data;
735 l_node = OSList_GetNextNode(p_list);
751 /* is_process: Check is a process is running.
753 int is_process(char *value, void *p_list_p)
755 OSList *p_list = (OSList *)p_list_p;
767 l_node = OSList_GetFirstNode(p_list);
772 pinfo = (Proc_Info *)l_node->data;
774 /* Checking if value matches */
775 if(pt_matches(pinfo->p_path, value))
778 char _b_msg[OS_SIZE_1024 +1];
780 _b_msg[OS_SIZE_1024] = '\0';
782 snprintf(_b_msg, OS_SIZE_1024, " Process: %s.",
785 /* Already present. */
786 if(_is_str_in_array(rootcheck.alert_msg, _b_msg))
791 while(rootcheck.alert_msg[i] && (i< 255))
794 if(!rootcheck.alert_msg[i])
795 os_strdup(_b_msg, rootcheck.alert_msg[i]);
800 l_node = OSList_GetNextNode(p_list);