ec72472d422805294a265b9a4602551701457ca6
[ossec-hids.git] / src / rootcheck / common_rcl.c
1 /* @(#) $Id$ */
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 2) 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
19
20 /* Types of values */
21 #define RKCL_TYPE_FILE      1
22 #define RKCL_TYPE_REGISTRY  2
23 #define RKCL_TYPE_PROCESS   3
24 #define RKCL_TYPE_DIR       4
25
26 #define RKCL_COND_ALL       0x001
27 #define RKCL_COND_ANY       0x002
28 #define RKCL_COND_REQ       0x004
29 #define RKCL_COND_INV       0x010 
30
31
32
33 /** char *_rkcl_getrootdir()
34  */
35 char *_rkcl_getrootdir(char *root_dir, int dir_size)
36 {
37     #ifdef WIN32
38     char final_file[2048 +1];
39     char *tmp;
40
41     final_file[0] = '\0';
42     final_file[2048] = '\0';
43     
44     ExpandEnvironmentStrings("%WINDIR%", final_file, 2047);
45
46     tmp = strchr(final_file, '\\');
47     if(tmp)
48     {
49         *tmp = '\0';
50         strncpy(root_dir, final_file, dir_size);
51         return(root_dir);
52     }
53     
54     return(NULL);
55
56     #endif
57
58     return(NULL);
59 }
60
61
62
63 /** char *_rkcl_getfp: Get next available buffer in file.
64  */
65 char *_rkcl_getfp(FILE *fp, char *buf)
66 {
67     while(fgets(buf, OS_SIZE_1024, fp) != NULL)
68     {
69         char *nbuf;
70
71         /* Removing end of line */
72         nbuf = strchr(buf, '\n');
73         if(nbuf)
74         {
75             *nbuf = '\0';
76         }
77
78         /* Assigning buf to be used */
79         nbuf = buf;
80
81
82         /* Excluding commented lines or blanked ones */
83         while(*nbuf != '\0')
84         {
85             if(*nbuf == ' ' || *nbuf == '\t')
86             {
87                 nbuf++;
88                 continue;
89             }
90             else if(*nbuf == '#')
91             {
92                 *nbuf = '\0';
93                 continue;
94             }
95             else
96             {
97                 break;
98             }
99         }
100
101         /* Going to next line if empty */
102         if(*nbuf == '\0')
103         {
104             continue;
105         }
106
107         return(nbuf);
108     }
109
110     return(NULL);
111 }
112
113
114
115 /** int _rkcl_is_name
116  */
117 int _rkcl_is_name(char *buf)
118 {
119     if(*buf == '[' && buf[strlen(buf) -1] == ']')
120     {
121         return(1);
122     }
123     return(0);
124 }
125
126
127
128 /**  int _rkcl_get_vars(vars, nbuf)
129  */
130 int _rkcl_get_vars(OSStore *vars, char *nbuf)
131 {
132     char *var_name;
133     char *var_value;
134     char *tmp;
135     
136     /* If not a variable, return 0 */
137     if(*nbuf != '$')
138     {
139         return(0);
140     }
141
142
143     /* Removing ; from the end. */
144     tmp = strchr(nbuf, ';');
145     if(tmp)
146     {
147         *tmp = '\0';
148     }
149     else
150     {
151         return(-1);
152     }
153     
154
155     /* Getting value. */
156     tmp = strchr(nbuf, '=');
157     if(tmp)
158     {
159         *tmp = '\0';
160         tmp++;
161     }
162     else
163     {
164         return(-1);
165     }
166
167
168     /* Dumping the variable options. */
169     os_strdup(nbuf, var_name);
170     os_strdup(tmp, var_value);
171
172
173     /* Adding entry to the storage */
174     OSStore_Put(vars, var_name, var_value);
175     return(1);
176 }
177
178
179
180 /** int _rkcl_get_name
181  */
182 char *_rkcl_get_name(char *buf, char *ref, int *condition)
183 {
184     char *tmp_location;
185     char *tmp_location2;
186     
187     *condition = 0;
188
189     /* Checking if name is valid */
190     if(!_rkcl_is_name(buf))
191     {
192         return(NULL);
193     }
194
195     /* Setting name */
196     buf++;
197     tmp_location = strchr(buf, ']');
198     if(!tmp_location)
199     {
200         return(NULL);
201     }
202     *tmp_location = '\0';
203     
204     
205     /* Getting condition */
206     tmp_location++;
207     if(*tmp_location != ' ' && tmp_location[1] != '[')
208     {
209         return(NULL);
210     }
211     tmp_location+=2;
212
213     tmp_location2 = strchr(tmp_location, ']');
214     if(!tmp_location2)
215     {
216         return(NULL);
217     }
218     *tmp_location2 = '\0';
219     tmp_location2++;
220     
221     
222     /* Getting condition */
223     if(strcmp(tmp_location, "all") == 0)
224     {
225         *condition |= RKCL_COND_ALL;
226     }
227     else if(strcmp(tmp_location,"any") == 0)
228     {
229         *condition |= RKCL_COND_ANY;
230     }
231     else if(strcmp(tmp_location,"any required") == 0)
232     {
233         *condition |= RKCL_COND_ANY;
234         *condition |= RKCL_COND_REQ;
235     }
236     else if(strcmp(tmp_location, "all required") == 0)
237     {
238         *condition |= RKCL_COND_ALL;
239         *condition |= RKCL_COND_REQ;
240     }
241     else
242     {
243         *condition = RKCL_COND_INV;
244         return(NULL);
245     }
246
247
248     /* Getting reference */
249     if(*tmp_location2 != ' ' && tmp_location2[1] != '[')
250     {
251         return(NULL);
252     }
253
254     tmp_location2+=2;
255     tmp_location = strchr(tmp_location2, ']');
256     if(!tmp_location)
257     {
258         return(NULL);
259     }
260     *tmp_location = '\0';
261
262     /* Copying reference */
263     strncpy(ref, tmp_location2, 255);    
264
265     return(strdup(buf));
266 }
267
268
269
270 /** char *_rkcl_get_pattern(char *value)
271  */
272 char *_rkcl_get_pattern(char *value)
273 {
274     while(*value != '\0')
275     {
276         if((*value == ' ') && (value[1] == '-') &&
277            (value[2] == '>') && (value[3] == ' '))
278         {
279             *value = '\0';
280             value += 4;
281
282             return(value);
283         }
284         value++;
285     }
286
287     return(NULL);
288 }
289
290
291
292 /** char *_rkcl_get_value
293  */
294 char *_rkcl_get_value(char *buf, int *type)
295 {
296     char *tmp_str;
297     char *value;
298
299     /* Zeroing type before using it  --make sure return is valid
300      * in case of error.
301      */
302     *type = 0;
303
304     value = strchr(buf, ':');
305     if(value == NULL)
306     {
307         return(NULL);
308     }
309
310     *value = '\0';
311     value++;
312     
313     tmp_str = strchr(value, ';');
314     if(tmp_str == NULL)
315     {
316         return(NULL);
317     }
318     *tmp_str = '\0';
319     
320
321     /* Getting types - removing negate flag (using later) */
322     if(*buf == '!')
323     {
324         buf++;
325     }
326     
327     if(strcmp(buf, "f") == 0)
328     {
329         *type = RKCL_TYPE_FILE;
330     }
331     else if(strcmp(buf, "r") == 0)
332     {
333         *type = RKCL_TYPE_REGISTRY;
334     }
335     else if(strcmp(buf, "p") == 0)
336     {
337         *type = RKCL_TYPE_PROCESS;
338     }
339     else if(strcmp(buf, "d") == 0)
340     {
341         *type = RKCL_TYPE_DIR;
342     }
343     else
344     {
345         return(NULL);
346     }
347
348     return(value);
349 }
350
351
352
353 /** int rkcl_get_entry:
354  */
355 int rkcl_get_entry(FILE *fp, char *msg, void *p_list_p)
356 {
357     int type = 0, condition = 0, root_dir_len = 0;
358     char *nbuf;
359     char buf[OS_SIZE_1024 +2];
360     char root_dir[OS_SIZE_1024 +2];
361     char final_file[2048 +1];
362     char ref[255 +1];
363
364     char *value;
365     char *name = NULL;
366
367     OSStore *vars;
368     OSList *p_list = (OSList *)p_list_p;
369
370
371     /* Cleaning up vars */
372     memset(buf, '\0', sizeof(buf));
373     memset(root_dir, '\0', sizeof(root_dir));
374     memset(final_file, '\0', sizeof(final_file));
375     memset(ref, '\0', sizeof(ref));
376
377     
378     root_dir_len = sizeof(root_dir) -1;
379
380
381     #ifdef WIN32
382     /* Getting Windows rootdir */
383     _rkcl_getrootdir(root_dir, root_dir_len);
384     if(root_dir[0] == '\0')
385     {
386         merror(INVALID_ROOTDIR, ARGV0);    
387     }
388     #endif    
389
390
391     /* Getting variables */
392     vars = OSStore_Create();
393     
394
395     /* We first read all variables -- they must be defined at the top. */
396     while(1)
397     {
398         int rc_code = 0;
399         nbuf = _rkcl_getfp(fp, buf);
400         if(nbuf == NULL)
401         {
402             goto clean_return;
403         }
404
405         rc_code = _rkcl_get_vars(vars, nbuf);
406         if(rc_code == 0)
407         {
408             break;
409         }
410         else if(rc_code == -1)
411         {
412             merror(INVALID_RKCL_VAR, ARGV0, nbuf);
413             goto clean_return;
414         }
415     }
416
417
418     /* Getting first name */
419     name = _rkcl_get_name(nbuf, ref, &condition);
420     if(name == NULL || condition == RKCL_COND_INV)
421     {
422         merror(INVALID_RKCL_NAME, ARGV0, nbuf);
423         goto clean_return;
424     }
425                                                                                 
426
427
428     /* Getting the real entries. */
429     do
430     {
431         int g_found = 0;
432         
433         
434         /* Getting entry name */
435         if(name == NULL)
436         {
437             merror(INVALID_RKCL_NAME, ARGV0, "NULL");
438             goto clean_return;
439         }
440
441         debug2("%s: DEBUG: Checking entry: '%s'.", ARGV0, name);
442
443
444         /* Getting each value */
445         do
446         {
447             int negate = 0;
448             int found = 0;
449             value = NULL;
450             
451             nbuf = _rkcl_getfp(fp, buf);
452             if(nbuf == NULL)
453             {
454                 break;
455             }
456
457             
458             /* We first try to get the name, looking for new entries */
459             if(_rkcl_is_name(nbuf))
460             {
461                 break;
462             }
463             
464             
465             /* Getting value to look for */
466             value = _rkcl_get_value(nbuf, &type);
467             if(value == NULL)
468             {
469                 merror(INVALID_RKCL_VALUE, ARGV0, nbuf);
470                 goto clean_return;
471             }
472
473
474             /* Getting negate value */
475             if(*value == '!')
476             {
477                 negate = 1;
478                 value++;
479             }
480
481
482             /* Checking for a file. */
483             if(type == RKCL_TYPE_FILE)
484             {
485                 char *pattern = NULL;
486                 char *f_value = NULL;
487
488
489                 pattern = _rkcl_get_pattern(value);
490                 f_value = value;
491
492
493                 /* Getting any variable. */
494                 if(value[0] == '$')
495                 {
496                     f_value = OSStore_Get(vars, value);
497                     if(!f_value)
498                     {
499                         merror(INVALID_RKCL_VAR, ARGV0, value);
500                         continue;
501                     }
502                 }
503                 
504
505                 #ifdef WIN32
506                 else if(value[0] == '\\')
507                 {
508                     final_file[0] = '\0';
509                     final_file[sizeof(final_file) -1] = '\0';
510                     
511                     snprintf(final_file, sizeof(final_file) -2, "%s%s", 
512                              root_dir, value);
513                     f_value = final_file;
514                 }
515                 else
516                 {
517                     final_file[0] = '\0';
518                     final_file[sizeof(final_file) -1] = '\0';
519                      
520                     ExpandEnvironmentStrings(value, final_file, 
521                                              sizeof(final_file) -2);
522                     f_value = final_file;
523                 }
524                 #endif
525
526
527                 debug2("%s: DEBUG: Checking file: '%s'.", ARGV0, f_value);
528                 if(rk_check_file(f_value, pattern))
529                 {
530                     debug1("%s: DEBUG: found file.", ARGV0);
531                     found = 1;
532                 }
533             }
534             
535
536             /* Checking for a registry entry */
537             else if(type == RKCL_TYPE_REGISTRY)
538             {
539                 char *entry = NULL;
540                 char *pattern = NULL;
541             
542                 
543                 /* Looking for additional entries in the registry
544                  * and a pattern to match.
545                  */
546                 entry = _rkcl_get_pattern(value);
547                 if(entry)
548                 {
549                     pattern = _rkcl_get_pattern(entry);
550                 }
551             
552             
553                 #ifdef WIN32
554                 debug2("%s: DEBUG: Checking registry: '%s'.", ARGV0, value);
555                 if(is_registry(value, entry, pattern))
556                 {
557                     debug2("%s: DEBUG: found registry.", ARGV0);
558                     found = 1;
559                 }
560                 #endif
561             }
562
563
564             /* Checking for a directory. */
565             else if(type == RKCL_TYPE_DIR)
566             {
567                 char *file = NULL;
568                 char *pattern = NULL;
569                 char *f_value = NULL;
570                 char *dir = NULL;
571
572                 
573                 file = _rkcl_get_pattern(value);
574                 if(file)
575                 {
576                     pattern = _rkcl_get_pattern(file);
577                 }
578
579
580                 /* Getting any variable. */
581                 if(value[0] == '$')
582                 {
583                     f_value = OSStore_Get(vars, value);
584                     if(!f_value)
585                     {
586                         merror(INVALID_RKCL_VAR, ARGV0, value);
587                         continue;
588                     }
589                 }
590                 else
591                 {
592                     f_value = value;
593                 }
594
595                 
596                 /* Checking for multiple, comma separated directories. */
597                 dir = f_value;
598                 f_value = strchr(dir, ',');
599                 if(f_value)
600                 {
601                     *f_value = '\0';
602                 }
603                 
604
605                 while(dir)
606                 {
607                     debug2("%s: Checking dir: %s", ARGV0, dir);
608                     if(rk_check_dir(dir, file, pattern))
609                     {
610                         debug2("%s: DEBUG: Found dir.", ARGV0);
611                         found = 1;
612                     }
613                     
614                     if(f_value)
615                     {
616                         *f_value = ',';
617                         f_value++;
618                         
619                         dir = f_value;
620                         
621                         f_value = strchr(dir, ',');
622                         if(f_value)
623                         {
624                             *f_value = '\0';
625                         }
626                     }
627                     else
628                     {
629                         dir = NULL;
630                     }
631                 }
632             }
633             
634
635             /* Checking for a process. */
636             else if(type == RKCL_TYPE_PROCESS)
637             {
638                 debug2("%s: DEBUG: Checking process: '%s'.", ARGV0, value);
639                 if(is_process(value, p_list))
640                 {
641                     debug2("%s: DEBUG: found process.", ARGV0);
642                     found = 1;
643                 }
644             }
645
646
647             /* Switching the values if ! is present */
648             if(negate)
649             {
650                 if(found)
651                 {
652                     found = 0;
653                 }
654                 else
655                 {
656                     found = 1;
657                 }
658             }
659
660
661             /** Checking the conditions **/
662             if(condition & RKCL_COND_ANY)
663             {
664                 debug2("%s: DEBUG: Condition ANY.", ARGV0);
665                 if(found)
666                 {
667                     g_found = 1;
668                 }
669             }
670             /* Condition for ALL */
671             else
672             {
673                 debug2("%s: DEBUG: Condition ALL.", ARGV0);
674                 if(found && (g_found != -1))
675                 {
676                     g_found = 1;
677                 }
678                 else
679                 {
680                     g_found = -1;
681                 }
682             }
683         }while(value != NULL);
684         
685         
686         /* Alerting if necessary */
687         if(g_found == 1)
688         {
689             int j = 0;
690             char op_msg[OS_SIZE_1024 +1];
691             char **p_alert_msg = rootcheck.alert_msg;
692
693             while(1) 
694             {
695                 if(ref[0] != '\0')
696                 {
697                     snprintf(op_msg, OS_SIZE_1024, "%s %s.%s"
698                             " Reference: %s .",msg, name, 
699                             p_alert_msg[j]?p_alert_msg[j]:"\0",
700                             ref);
701                 }
702                 else
703                 {
704                     snprintf(op_msg, OS_SIZE_1024, "%s %s.%s",msg, 
705                             name, p_alert_msg[j]?p_alert_msg[j]:"\0");
706                 }
707
708                 if((type == RKCL_TYPE_DIR) || (j == 0))
709                 {
710                     notify_rk(ALERT_POLICY_VIOLATION, op_msg);
711                 }
712
713                 if(p_alert_msg[j])
714                 {
715                     free(p_alert_msg[j]);
716                     p_alert_msg[j] = NULL;
717                     j++;
718
719                     if(!p_alert_msg[j])
720                         break;
721                 }
722                 else
723                 {
724                     break;
725                 }
726             }
727         }
728         else
729         {
730             int j = 0;
731             while(rootcheck.alert_msg[j])
732             {
733                 free(rootcheck.alert_msg[j]);
734                 rootcheck.alert_msg[j] = NULL;
735                 j++;
736             }
737
738
739             /* Checking if this entry is required for the rest of the file. */
740             if(condition & RKCL_COND_REQ)
741             {
742                 goto clean_return;
743             }
744         }
745         
746
747         /* Ending if we don't have anything else. */
748         if(!nbuf)
749         {
750             goto clean_return;
751         }
752
753
754         /* Cleaning up name. */
755         if(name)
756         {
757             free(name);
758             name = NULL;
759         }
760         
761
762         /* Getting name already read */
763         name = _rkcl_get_name(nbuf, ref, &condition);
764         if(!name)
765         {
766             merror(INVALID_RKCL_NAME, ARGV0, nbuf);
767             goto clean_return;
768         }
769     }while(nbuf != NULL);
770
771
772
773     /* Cleaning up the memory */
774     clean_return:
775     if(name)
776     {
777         free(name);
778         name = NULL;
779     }
780     vars = OSStore_Free(vars);
781     
782     
783     return(1);
784 }
785
786
787 /* EOF */