Imported Upstream version 2.3
[ossec-hids.git] / src / rootcheck / common.c
1 /* @(#) $Id: common.c,v 1.25 2009/06/24 18:53:07 dcid Exp $ */
2
3 /* Copyright (C) 2009 Trend Micro Inc.
4  * All right reserved.
5  *
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 3) as published by the FSF - Free Software
9  * Foundation
10  *
11  * License details at the LICENSE file included with OSSEC or 
12  * online at: http://www.ossec.net/main/license/ .
13  */
14
15  
16 #include "shared.h"
17 #include "rootcheck.h"
18 #include "os_regex/os_regex.h" 
19
20
21
22 /** Checks if the specified string is already in the array.
23  */
24 int _is_str_in_array(char **ar, char *str)
25 {
26     while(*ar)
27     {
28         if(strcmp(*ar, str) == 0)
29         {
30             return(1);
31         }
32         ar++;
33     }
34     return(0);
35 }
36
37
38
39 /** int rk_check_dir(char *dir, char *file, char *pattern)
40  */
41 int rk_check_dir(char *dir, char *file, char *pattern)
42 {
43     int ret_code = 0;
44     char f_name[PATH_MAX +2];
45     struct dirent *entry;
46     struct stat statbuf_local;
47     DIR *dp = NULL;
48
49
50     f_name[PATH_MAX +1] = '\0';
51
52
53     dp = opendir(dir);
54     if(!dp)
55         return(0);
56
57
58     while((entry = readdir(dp)) != NULL)
59     {
60         /* Just ignore . and ..  */
61         if((strcmp(entry->d_name,".") == 0) ||
62            (strcmp(entry->d_name,"..") == 0)) 
63         {
64             continue;
65         }
66
67
68         /* Creating new file + path string */
69         snprintf(f_name, PATH_MAX +1, "%s/%s",dir, entry->d_name);
70
71         
72         /* Checking if the read entry, matches the provided file name. */
73         if(strncasecmp(file, "r:", 2) == 0)
74         {
75             if(OS_Regex(file +2, entry->d_name))
76             {
77                 if(rk_check_file(f_name, pattern))
78                 {
79                     ret_code = 1;
80                 }
81             }
82         }
83         
84         /* Trying without regex. */
85         else
86         {
87             if(OS_Match2(file, entry->d_name))
88             {
89                 if(rk_check_file(f_name, pattern))
90                 {
91                     ret_code = 1;
92                 }
93             }
94         }
95
96         
97         /* Checking if file is a directory */
98         if(lstat(f_name, &statbuf_local) == 0)
99         {
100             if(S_ISDIR(statbuf_local.st_mode))
101             {
102                 if(rk_check_dir(f_name, file, pattern))
103                 {
104                     ret_code = 1;
105                 }
106             }
107         }
108     }
109
110     closedir(dp);
111     return(ret_code);
112
113 }
114
115
116
117 /** int rk_check_file(char *value, char *pattern)
118  */
119 int rk_check_file(char *file, char *pattern)
120 {
121     char *split_file;
122     
123     FILE *fp;
124     char buf[OS_SIZE_2048 +1];
125     
126     
127     /* If string is null, we don't match */
128     if(file == NULL)
129     {
130         return(0);
131     }
132
133
134     /* Checking if the file is divided */
135     split_file = strchr(file, ',');
136     if(split_file)
137     {
138         *split_file = '\0';
139         split_file++;
140     }
141
142
143     /* Getting each file */
144     do
145     {
146         
147
148         /* If we don't have a pattern, just check if the file/dir is there */
149         if(pattern == NULL)
150         {
151             if(is_file(file))
152             {
153                 int i = 0;
154                 char _b_msg[OS_SIZE_1024 +1];
155
156                 _b_msg[OS_SIZE_1024] = '\0';
157                 snprintf(_b_msg, OS_SIZE_1024, " File: %s.",
158                          file);
159
160                 /* Already present. */
161                 if(_is_str_in_array(rootcheck.alert_msg, _b_msg))
162                 {
163                     return(1);
164                 }
165
166                 while(rootcheck.alert_msg[i] && (i < 255))
167                     i++;
168                 
169                 if(!rootcheck.alert_msg[i])
170                     os_strdup(_b_msg, rootcheck.alert_msg[i]);
171
172                 return(1);
173             }
174         }
175
176         else
177         {
178             /* Checking for a content in the file */
179             fp = fopen(file, "r");
180             if(fp)
181             {
182
183                 buf[OS_SIZE_2048] = '\0';
184                 while(fgets(buf, OS_SIZE_2048, fp) != NULL)
185                 {
186                     char *nbuf;
187
188                     /* Removing end of line */
189                     nbuf = strchr(buf, '\n');
190                     if(nbuf)
191                     {
192                         *nbuf = '\0';
193                     }
194
195
196                     #ifdef WIN32
197                     /* Removing end of line */
198                     nbuf = strchr(buf, '\r');
199                     if(nbuf)
200                     {
201                         *nbuf = '\0';
202                     }
203                     #endif
204
205
206                     /* Matched */
207                     if(pt_matches(buf, pattern))
208                     {
209                         int i = 0;
210                         char _b_msg[OS_SIZE_1024 +1];
211
212
213                         /* Closing the file before dealing with the alert. */
214                         fclose(fp);
215
216                         /* Generating the alert itself. */
217                         _b_msg[OS_SIZE_1024] = '\0';
218                         snprintf(_b_msg, OS_SIZE_1024, " File: %s.",
219                                  file);
220                         
221                         /* Already present. */
222                         if(_is_str_in_array(rootcheck.alert_msg, _b_msg))
223                         {
224                             return(1);
225                         }
226
227                         while(rootcheck.alert_msg[i] && (i < 255))
228                             i++;
229
230                         if(!rootcheck.alert_msg[i])
231                         os_strdup(_b_msg, rootcheck.alert_msg[i]);
232
233                         return(1);
234                     }
235                 }
236
237                 fclose(fp);
238             }
239         }
240
241         if(split_file)
242         {
243             file = split_file;
244             split_file = strchr(split_file, ',');
245             if(split_file)
246             {
247                 split_file++;
248             }
249         }
250         
251         
252     }while(split_file);
253
254
255     return(0);
256 }
257
258
259
260 /** int pt_matches(char *str, char *pattern)
261  * Checks if the specific pattern is present on str.
262  * A pattern can be preceeded by:
263  *                                =: (for equal) - default - strcasecmp
264  *                                r: (for ossec regexes)
265  *                                >: (for strcmp greater)
266  *                                <: (for strcmp  lower)    
267  *
268  * Multiple patterns can be specified by using " && " between them.
269  * All of them must match for it to return true.
270  */
271 int pt_matches(char *str, char *pattern)
272 {
273     int neg = 0;
274     int ret_code = 0;
275     char *tmp_pt = pattern;
276     char *tmp_ret = NULL;
277
278
279     /* If string we null, we don't match */
280     if(str == NULL)
281     {
282         return(0);
283     }
284     
285     while(tmp_pt != NULL)
286     {
287         /* We first look for " && " */
288         tmp_pt = strchr(pattern, ' ');
289         if(tmp_pt && tmp_pt[1] == '&' && tmp_pt[2] == '&' && tmp_pt[3] == ' ')
290         {
291             /* Marking pointer to clean it up */        
292             tmp_ret = tmp_pt;
293                     
294             *tmp_pt = '\0';
295             tmp_pt += 4;
296         }
297         else
298         {
299             tmp_pt = NULL;
300         }
301
302
303         /* Checking for negate values */
304         neg = 0;
305         ret_code = 0;
306         if(*pattern == '!')
307         {
308             pattern++;
309             neg = 1;
310         }
311         
312
313         /* Doing strcasecmp */
314         if(strncasecmp(pattern, "=:", 2) == 0)
315         {
316             pattern += 2;
317             if(strcasecmp(pattern, str) == 0)
318             {
319                 ret_code = 1;
320             }
321         }
322         else if(strncasecmp(pattern, "r:", 2) == 0)
323         {
324             pattern += 2;
325             if(OS_Regex(pattern, str))
326             {
327                 ret_code = 1;
328             }
329         }
330         else if(strncasecmp(pattern, "<:", 2) == 0)
331         {
332             pattern += 2;
333             if(strcmp(pattern, str) < 0)
334             {
335                 ret_code = 1;
336             }
337         }
338         else if(strncasecmp(pattern, ">:", 2) == 0)
339         {
340             pattern += 2;
341             if(strcmp(pattern, str) > 0)
342             {
343                 ret_code = 1;
344             }
345         }
346         else
347         {
348             #ifdef WIN32
349             char final_file[2048 +1];
350             
351             /* Try to get Windows variable */
352             if(*pattern == '%')
353             {
354                 final_file[0] = '\0';
355                 final_file[2048] = '\0';
356
357                 ExpandEnvironmentStrings(pattern, final_file, 2047);
358             }
359             else
360             {
361                 strncpy(final_file, pattern, 2047);
362             }
363
364             /* Comparing against the expanded variable */
365             if(strcasecmp(final_file, str) == 0)
366             {
367                 ret_code = 1;
368             }
369             
370             #else
371             if(strcasecmp(pattern, str) == 0)
372             {
373                 ret_code = 1;
374             }
375
376             #endif
377         }
378
379         /* Fixing tmp_ret entry */
380         if(tmp_ret != NULL)
381         {
382             *tmp_ret = ' ';
383             tmp_ret = NULL;
384         }
385
386         
387         /* If we have "!", return true if we don't match */
388         if(neg == 1)
389         {
390             if(ret_code)
391             {
392                 ret_code = 0;
393                 break;
394             }
395         }
396         else
397         {
398             if(!ret_code)
399             {
400                 ret_code = 0;
401                 break;
402             }
403         }
404         
405         ret_code = 1;
406         pattern = tmp_pt;
407     }
408
409     return(ret_code);
410 }
411
412
413
414 /** char *normalize_string
415  * Normalizes a string, removing white spaces and tabs
416  * from the begining and the end of it.
417  */
418 char *normalize_string(char *str)
419 {
420     int str_sz = strlen(str) -1;
421     
422     while(*str != '\0')
423     {
424         if(*str == ' ' || *str == '\t')
425         {
426             str++;
427         }
428         else
429         {
430             break;
431         }
432     }
433
434     while(str[str_sz] == ' ' || str[str_sz] == '\t')
435     {
436         str[str_sz] = '\0';
437         str_sz--;
438     }
439
440     return(str);
441 }
442
443
444
445 /** int isfile_ondir(char *file, char *dir)
446  * Checks is 'file' is present on 'dir' using readdir
447  */
448 int isfile_ondir(char *file, char *dir)
449 {
450     DIR *dp = NULL;
451     struct dirent *entry;
452     dp = opendir(dir);
453     
454     if(!dp)
455         return(0);
456
457     while((entry = readdir(dp)) != NULL)
458     {
459         if(strcmp(entry->d_name, file) == 0)
460         {
461             closedir(dp);
462             return(1);
463         }
464     }
465     
466     closedir(dp);
467     return(0);
468 }
469
470
471
472 /* is_file: Check if the file is present
473  * by different attempts (to try to avoid syscall hidding).
474  */
475 int is_file(char *file_name)
476 {
477     int ret = 0;
478     
479     struct stat statbuf;
480     FILE *fp = NULL;
481     DIR *dp = NULL;
482
483
484     #ifndef WIN32
485     
486     char curr_dir[1024];
487     
488     char *file_dirname;
489     char *file_basename;
490     
491
492     curr_dir[1023] = '\0';
493
494     if(!getcwd(curr_dir, 1022))
495     {
496         return(0);
497     }
498
499     /* Getting dir name */
500     file_basename = strrchr(file_name, '/');
501     if(!file_basename)
502     {
503         merror("%s: RK: Invalid file name: %s!", ARGV0, file_name);
504         return(0);
505     }
506
507     
508     /* If file_basename == file_name, then the file
509      * only has one slash at the beginning.
510      */
511     if(file_basename != file_name)
512     {
513         /* Dir name and base name are now set */
514         *file_basename = '\0';
515         file_basename++;
516         file_dirname = file_name;
517
518         /** chdir test **/
519         if(chdir(file_dirname) == 0)
520         {
521             if(chdir(file_basename) == 0)
522             {
523                 ret = 1;
524             }
525             /* Checking errno (if file exists, but it is not
526              * a directory.
527              */
528             else if(errno == ENOTDIR)
529             {
530                 ret = 1;
531             }
532
533             /** Trying open dir **/
534             dp = opendir(file_basename);
535             if(dp)
536             {
537                 closedir(dp);
538                 ret = 1;
539             }
540             else if(errno == ENOTDIR)
541             {
542                 ret = 1;
543             }
544
545             /* Returning to the previous directory */
546             chdir(curr_dir);
547         }
548
549
550         file_basename--;
551         *file_basename = '/';
552
553     }
554     else
555     {
556         if(chdir(file_name) == 0)
557         {
558             ret = 1;
559
560             /* Returning to the previous directory */
561             chdir(curr_dir);
562         }
563         else if(errno == ENOTDIR)
564         {
565             ret = 1;
566         }
567     }
568     
569     #else
570     dp = opendir(file_name);
571     if(dp)
572     {
573         closedir(dp);
574         ret = 1;
575     }
576                                                                                 
577     #endif /* WIN32 */
578
579     
580     /* Trying other calls */
581     if( (stat(file_name, &statbuf) < 0) &&
582         #ifndef WIN32
583         (access(file_name, F_OK) < 0) &&
584         #endif
585         ((fp = fopen(file_name, "r")) == NULL))
586     {
587         return(ret);
588     }
589
590     /* must close it over here */
591     if(fp)
592         fclose(fp);
593     
594     return(1);
595 }
596
597
598
599 /*  del_plist:. Deletes the process list
600  */
601 int del_plist(void *p_list_p)
602 {
603     OSList *p_list = (OSList *)p_list_p;
604     OSListNode *l_node;
605     OSListNode *p_node = NULL;
606
607     if(p_list == NULL)
608     {
609         return(0);
610     }
611
612     l_node = OSList_GetFirstNode(p_list);
613     while(l_node)
614     {
615         Proc_Info *pinfo;
616
617         pinfo = (Proc_Info *)l_node->data;
618
619         if(pinfo->p_name)
620         {
621             free(pinfo->p_name);
622         }
623
624         if(pinfo->p_path)
625         {
626             free(pinfo->p_path);
627         }
628         
629         free(l_node->data);
630
631         if(p_node)
632         {
633             free(p_node);
634             p_node = NULL;
635         }
636         p_node = l_node;
637
638         l_node = OSList_GetNextNode(p_list);
639     }
640
641     if(p_node)
642     {
643         free(p_node);
644         p_node = NULL;
645     }
646
647     free(p_list);
648
649     return(1);
650 }
651
652
653
654 /* is_process: Check is a process is running.
655  */
656 int is_process(char *value, void *p_list_p)
657 {
658     OSList *p_list = (OSList *)p_list_p;
659     OSListNode *l_node;
660     if(p_list == NULL)
661     {
662         return(0);
663     }
664     if(!value)
665     {
666         return(0);
667     }
668
669
670     l_node = OSList_GetFirstNode(p_list);
671     while(l_node)
672     {
673         Proc_Info *pinfo;
674
675         pinfo = (Proc_Info *)l_node->data;
676
677         /* Checking if value matches */
678         if(pt_matches(pinfo->p_path, value))
679         {
680             int i = 0;
681             char _b_msg[OS_SIZE_1024 +1];
682
683             _b_msg[OS_SIZE_1024] = '\0';
684             
685             snprintf(_b_msg, OS_SIZE_1024, " Process: %s.",
686                      pinfo->p_path);
687
688             /* Already present. */
689             if(_is_str_in_array(rootcheck.alert_msg, _b_msg))
690             {
691                 return(1);
692             }
693             
694             while(rootcheck.alert_msg[i] && (i< 255))
695                 i++;
696
697             if(!rootcheck.alert_msg[i])
698                 os_strdup(_b_msg, rootcheck.alert_msg[i]);
699
700             return(1);
701         }
702
703         l_node = OSList_GetNextNode(p_list);
704     }
705
706     return(0);
707
708 }
709  
710  
711
712 /* EOF */