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