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
11 #include "rootcheck.h"
12 #include "os_regex/os_regex.h"
15 static int _is_str_in_array(char *const *ar, const char *str);
18 /* Check if the specified string is already in the array */
19 static int _is_str_in_array(char *const *ar, const char *str)
22 if (strcmp(*ar, str) == 0) {
30 int rk_check_dir(const char *dir, const char *file, char *pattern)
33 char f_name[PATH_MAX + 2];
35 struct stat statbuf_local;
38 f_name[PATH_MAX + 1] = '\0';
45 while ((entry = readdir(dp)) != NULL) {
47 if ((strcmp(entry->d_name, ".") == 0) ||
48 (strcmp(entry->d_name, "..") == 0)) {
52 /* Create new file + path string */
53 snprintf(f_name, PATH_MAX + 1, "%s/%s", dir, entry->d_name);
55 /* Check if the read entry matches the provided file name */
56 if (strncasecmp(file, "r:", 2) == 0) {
57 if (OS_Regex(file + 2, entry->d_name)) {
58 if (rk_check_file(f_name, pattern)) {
63 /* ... otherwise try without regex */
64 if (OS_Match2(file, entry->d_name)) {
65 if (rk_check_file(f_name, pattern)) {
71 /* Check if file is a directory */
72 if (lstat(f_name, &statbuf_local) == 0) {
73 if (S_ISDIR(statbuf_local.st_mode)) {
74 if (rk_check_dir(f_name, file, pattern)) {
86 int rk_check_file(char *file, char *pattern)
92 char buf[OS_SIZE_2048 + 1];
98 /* Check if the file is divided */
99 split_file = strchr(file, ',');
107 /* If we don't have a pattern, just check if the file/dir is there */
108 if (pattern == NULL) {
111 char _b_msg[OS_SIZE_1024 + 1];
113 _b_msg[OS_SIZE_1024] = '\0';
114 snprintf(_b_msg, OS_SIZE_1024, " File: %s.",
117 /* Already present */
118 if (_is_str_in_array(rootcheck.alert_msg, _b_msg)) {
122 while (rootcheck.alert_msg[i] && (i < 255)) {
126 if (!rootcheck.alert_msg[i]) {
127 os_strdup(_b_msg, rootcheck.alert_msg[i]);
133 full_negate = pt_check_negate(pattern);
134 /* Check for content in the file */
135 debug1("checking file: %s", file);
136 fp = fopen(file, "r");
139 debug1(" starting new file: %s", file);
140 buf[OS_SIZE_2048] = '\0';
141 while (fgets(buf, OS_SIZE_2048, fp) != NULL) {
144 /* Remove end of line */
145 nbuf = strchr(buf, '\n');
150 /* Remove end of line */
151 nbuf = strchr(buf, '\r');
157 pt_result = pt_matches(buf, pattern);
158 debug1("Buf == \"%s\"", buf);
159 debug1("Pattern == \"%s\"", pattern);
160 debug1("pt_result == %d and full_negate == %d", pt_result, full_negate);
161 if ((pt_result == 1 && full_negate == 0) ) {
162 debug1("alerting file %s on line %s", file, buf);
164 char _b_msg[OS_SIZE_1024 + 1];
166 /* Close the file before dealing with the alert */
169 /* Generate the alert itself */
170 _b_msg[OS_SIZE_1024] = '\0';
171 snprintf(_b_msg, OS_SIZE_1024, " File: %s.",
174 /* Already present */
175 if (_is_str_in_array(rootcheck.alert_msg, _b_msg)) {
179 while (rootcheck.alert_msg[i] && (i < 255)) {
183 if (!rootcheck.alert_msg[i]) {
184 os_strdup(_b_msg, rootcheck.alert_msg[i]);
188 } else if ((pt_result == 0 && full_negate == 1) ) {
189 /* Found a full+negate match so no longer need to search
190 * break out of loop and make sure the full negate does
193 debug1("found a complete match for full_negate");
201 if (full_negate == 1) {
202 debug1("full_negate alerting - file %s", file);
204 char _b_msg[OS_SIZE_1024 + 1];
206 /* Generate the alert itself */
207 _b_msg[OS_SIZE_1024] = '\0';
208 snprintf(_b_msg, OS_SIZE_1024, " File: %s.",
211 /* Already present */
212 if (_is_str_in_array(rootcheck.alert_msg, _b_msg)) {
216 while (rootcheck.alert_msg[i] && (i < 255)) {
220 if (!rootcheck.alert_msg[i]) {
221 os_strdup(_b_msg, rootcheck.alert_msg[i]);
231 split_file = strchr(split_file, ',');
238 } while (split_file);
243 /* Check if the pattern is all negate values */
244 int pt_check_negate(const char *pattern)
246 char *mypattern = NULL;
247 os_strdup(pattern, mypattern);
248 char *tmp_pt = mypattern;
249 char *tmp_pattern = mypattern;
251 while (tmp_pt != NULL) {
252 /* First look for " && " */
253 tmp_pt = strchr(tmp_pattern, ' ');
254 if (tmp_pt && tmp_pt[1] == '&' && tmp_pt[2] == '&' && tmp_pt[3] == ' ') {
261 if (*tmp_pattern != '!') {
266 tmp_pattern = tmp_pt;
269 debug1("pattern: %s is fill_negate", pattern);
274 /* Checks if the specific pattern is present on str.
275 * A pattern can be preceded by:
276 * =: (for equal) - default - strcasecmp
277 * r: (for ossec regexes)
278 * >: (for strcmp greater)
279 * <: (for strcmp lower)
281 * Multiple patterns can be specified by using " && " between them.
282 * All of them must match for it to return true.
284 int pt_matches(const char *str, char *pattern)
288 char *tmp_pt = pattern;
289 char *tmp_ret = NULL;
295 while (tmp_pt != NULL) {
296 /* First look for " && " */
297 tmp_pt = strchr(pattern, ' ');
298 if (tmp_pt && tmp_pt[1] == '&' && tmp_pt[2] == '&' && tmp_pt[3] == ' ') {
299 /* Mark pointer to clean it up */
308 /* Check for negate values */
311 if (*pattern == '!') {
316 /* Do the actual comparison */
317 if (strncasecmp(pattern, "=:", 2) == 0) {
319 if (strcasecmp(pattern, str) == 0) {
322 } else if (strncasecmp(pattern, "r:", 2) == 0) {
324 if (OS_Regex(pattern, str)) {
325 debug1("pattern: %s matches %s.", pattern, str);
328 } else if (strncasecmp(pattern, "<:", 2) == 0) {
330 if (strcmp(pattern, str) < 0) {
333 } else if (strncasecmp(pattern, ">:", 2) == 0) {
335 if (strcmp(pattern, str) > 0) {
340 char final_file[2048 + 1];
342 /* Try to get Windows variable */
343 if (*pattern == '%') {
344 final_file[0] = '\0';
345 final_file[2048] = '\0';
347 ExpandEnvironmentStrings(pattern, final_file, 2047);
349 strncpy(final_file, pattern, 2047);
352 /* Compare against the expanded variable */
353 if (strcasecmp(final_file, str) == 0) {
357 if (strcasecmp(pattern, str) == 0) {
362 /* Fix tmp_ret entry */
363 if (tmp_ret != NULL) {
368 /* If we have "!", return true if we don't match */
388 /* Normalizes a string, removing white spaces and tabs
389 * from the beginning and the end of it.
391 char *normalize_string(char *str)
393 size_t str_sz = strlen(str);
394 /* Return zero-length str as is */
400 /* Remove trailing spaces */
401 while (str[str_sz] == ' ' || str[str_sz] == '\t') {
406 str[str_sz--] = '\0';
408 /* ignore leading spaces */
409 while (*str != '\0') {
410 if (*str == ' ' || *str == '\t') {
420 /* Check if 'file' is present on 'dir' using readdir */
421 int isfile_ondir(const char *file, const char *dir)
424 struct dirent *entry;
431 while ((entry = readdir(dp)) != NULL) {
432 if (strcmp(entry->d_name, file) == 0) {
442 /* Check if the file is present using several methods
443 * to avoid being tricked by syscall hiding
445 int is_file(char *file_name)
457 curr_dir[1023] = '\0';
459 if (!getcwd(curr_dir, 1022)) {
464 file_basename = strrchr(file_name, '/');
465 if (!file_basename) {
466 merror("%s: RK: Invalid file name: %s!", ARGV0, file_name);
470 /* If file_basename == file_name, then the file
471 * only has one slash at the beginning
473 if (file_basename != file_name) {
474 /* Dir name and base name are now set */
475 *file_basename = '\0';
477 file_dirname = file_name;
480 if (chdir(file_dirname) == 0) {
481 if (chdir(file_basename) == 0) {
484 /* Check errno (if file exists, but it is not
487 else if (errno == ENOTDIR) {
491 /* Trying open dir */
492 dp = opendir(file_basename);
496 } else if (errno == ENOTDIR) {
500 /* Return to the previous directory */
501 if (chdir(curr_dir) == -1) {
502 merror(CHDIR_ERROR, ARGV0, curr_dir, errno, strerror(errno));
508 *file_basename = '/';
510 if (chdir(file_name) == 0) {
513 /* Return to the previous directory */
514 if (chdir(curr_dir) == -1) {
515 merror(CHDIR_ERROR, ARGV0, curr_dir, errno, strerror(errno));
518 } else if (errno == ENOTDIR) {
524 dp = opendir(file_name);
530 /* Trying other calls */
531 if ( (stat(file_name, &statbuf) < 0) &&
533 (access(file_name, F_OK) < 0) &&
535 ((fp = fopen(file_name, "r")) == NULL)) {
546 /* Delete the process list */
547 int del_plist(OSList *p_list)
550 OSListNode *p_node = NULL;
552 if (p_list == NULL) {
556 l_node = OSList_GetFirstNode(p_list);
560 pinfo = (Proc_Info *)l_node->data;
578 l_node = OSList_GetNextNode(p_list);
591 /* Check if a process is running */
592 int is_process(char *value, OSList *p_list)
595 if (p_list == NULL) {
602 l_node = OSList_GetFirstNode(p_list);
606 pinfo = (Proc_Info *)l_node->data;
608 /* Check if value matches */
609 if (pt_matches(pinfo->p_path, value)) {
611 char _b_msg[OS_SIZE_1024 + 1];
613 _b_msg[OS_SIZE_1024] = '\0';
615 snprintf(_b_msg, OS_SIZE_1024, " Process: %s.",
618 /* Already present */
619 if (_is_str_in_array(rootcheck.alert_msg, _b_msg)) {
623 while (rootcheck.alert_msg[i] && (i < 255)) {
627 if (!rootcheck.alert_msg[i]) {
628 os_strdup(_b_msg, rootcheck.alert_msg[i]);
634 l_node = OSList_GetNextNode(p_list);