Imported Upstream version 2.5.1
[ossec-hids.git] / src / shared / validate_op.c
1 /* @(#) $Id$ */
2
3 /* Copyright (C) 2009 Trend Micro Inc.
4  * All rights 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
12 /* Part of the OSSEC.
13  * Available at http://www.ossec.net
14  */
15
16
17
18 #include "shared.h"
19 char *ip_address_regex = 
20      "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}/?" 
21      "([0-9]{0,2}|[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})$";
22
23 /* Global vars */
24 int _mask_inited = 0;
25 int _netmasks[33];
26
27
28 /* Read the file and return a string the matches the following
29  * format: high_name.low_name.
30  * If return is not null, value must be free.
31  */
32 static char *_read_file(char *high_name, char *low_name, char *defines_file)
33 {
34     FILE *fp;
35     char def_file[OS_FLSIZE +1];
36     char buf[OS_SIZE_1024 +1];
37     char *buf_pt;
38     char *tmp_buffer;
39     char *ret;
40     
41     #ifndef WIN32
42     if(isChroot())
43     {
44         snprintf(def_file,OS_FLSIZE,"%s", defines_file);
45     }
46     else
47     {
48         snprintf(def_file,OS_FLSIZE,"%s%s",DEFAULTDIR, defines_file);
49     }
50     #else
51     snprintf(def_file,OS_FLSIZE,"%s", defines_file);
52     #endif
53
54                                                         
55     fp = fopen(def_file, "r");
56     if(!fp)
57     {
58         if(strcmp(defines_file, OSSEC_LDEFINES) != 0)
59         {
60             merror(FOPEN_ERROR, __local_name, def_file);
61         }
62         return(NULL);
63     }
64
65     /* Invalid call */
66     if(!high_name || !low_name)
67     {
68         merror(NULL_ERROR, __local_name);
69         fclose(fp);
70         return(NULL);
71     }
72
73     /* Reading it */
74     buf[OS_SIZE_1024] = '\0';
75     while(fgets(buf, OS_SIZE_1024 , fp) != NULL)
76     {
77         /* Commented or blank lines */
78         if(buf[0] == '#' || buf[0] == ' ' || buf[0] == '\n')
79         {
80             continue;
81         }
82
83         /* Messages not formatted correctly */
84         buf_pt = strchr(buf, '.');
85         if(!buf_pt)
86         {
87             merror(FGETS_ERROR, __local_name, def_file, buf);
88             continue;
89         }
90
91         /* Checking for the high name */
92         *buf_pt = '\0'; buf_pt++;
93         if(strcmp(buf, high_name) != 0)
94         {
95             continue;
96         }
97
98         tmp_buffer = buf_pt;
99         
100         /* Getting the equal */
101         buf_pt = strchr(buf_pt, '=');
102         if(!buf_pt)
103         {
104             merror(FGETS_ERROR, __local_name, def_file, buf);
105             continue;
106         }
107
108         /* Checking for the low name */
109         *buf_pt = '\0'; buf_pt++;
110         if(strcmp(tmp_buffer, low_name) != 0)
111         {
112             continue;
113         }
114
115         /* Removing new lines or anything that we cause errors */
116         tmp_buffer = strrchr(buf_pt, '\n');
117         if(tmp_buffer)
118         {
119             *tmp_buffer = '\0';
120         }
121
122         tmp_buffer = strrchr(buf_pt, '\r');
123         if(tmp_buffer)
124         {
125             *tmp_buffer = '\0';
126         }
127         
128         os_strdup(buf_pt, ret);
129         fclose(fp);
130         return(ret);
131     }
132     
133     fclose(fp);
134     return(NULL);
135 }
136
137
138
139 /* Getting the netmask based on the integer value. */
140 int getNetmask(int mask, char *strmask, int size)
141 {
142     int i = 0;
143
144     strmask[0] = '\0';
145
146     if(mask == 0)
147     {
148         snprintf(strmask, size, "/any");
149         return(1);
150     }
151
152     for(i = 0;i<=31;i++)
153     {
154         if(htonl(_netmasks[i]) == mask)
155         {
156             snprintf(strmask, size, "/%d", i);
157             break;
158         }
159     }
160
161     return(1);
162 }
163
164
165
166 /* Initialize netmasks -- took from snort util.c */
167 void _init_masks()
168 {
169     _mask_inited = 1;
170     _netmasks[0] = 0x0;
171     _netmasks[1] = 0x80000000;
172     _netmasks[2] = 0xC0000000;
173     _netmasks[3] = 0xE0000000;
174     _netmasks[4] = 0xF0000000;
175     _netmasks[5] = 0xF8000000;
176     _netmasks[6] = 0xFC000000;
177     _netmasks[7] = 0xFE000000;
178     _netmasks[8] = 0xFF000000;
179     _netmasks[9] = 0xFF800000;
180     _netmasks[10] = 0xFFC00000;
181     _netmasks[11] = 0xFFE00000;
182     _netmasks[12] = 0xFFF00000;
183     _netmasks[13] = 0xFFF80000;
184     _netmasks[14] = 0xFFFC0000;
185     _netmasks[15] = 0xFFFE0000;
186     _netmasks[16] = 0xFFFF0000;
187     _netmasks[17] = 0xFFFF8000;
188     _netmasks[18] = 0xFFFFC000;
189     _netmasks[19] = 0xFFFFE000;
190     _netmasks[20] = 0xFFFFF000;
191     _netmasks[21] = 0xFFFFF800;
192     _netmasks[22] = 0xFFFFFC00;
193     _netmasks[23] = 0xFFFFFE00;
194     _netmasks[24] = 0xFFFFFF00;
195     _netmasks[25] = 0xFFFFFF80;
196     _netmasks[26] = 0xFFFFFFC0;
197     _netmasks[27] = 0xFFFFFFE0;
198     _netmasks[28] = 0xFFFFFFF0;
199     _netmasks[29] = 0xFFFFFFF8;
200     _netmasks[30] = 0xFFFFFFFC;
201     _netmasks[31] = 0xFFFFFFFE;
202     _netmasks[32] = 0xFFFFFFFF;
203 }
204
205
206 /** getDefine_Int.
207  * Gets an integer definition. This function always return on
208  * success or exit on error.
209  */
210 int getDefine_Int(char *high_name, char *low_name, int min, int max)
211 {
212     int ret;
213     char *value;
214     char *pt;
215
216     
217     /* We first try to read from the local define file. */
218     value = _read_file(high_name, low_name, OSSEC_LDEFINES);
219     if(!value)
220     {
221         value = _read_file(high_name, low_name, OSSEC_DEFINES);
222         if(!value)
223             ErrorExit(DEF_NOT_FOUND, __local_name, high_name, low_name);
224     }
225
226     pt = value;
227     while(*pt != '\0')
228     {
229         if(!isdigit((int)*pt))
230         {
231             ErrorExit(INV_DEF, __local_name, high_name, low_name, value);
232         }
233         pt++;
234     }
235
236     ret = atoi(value);
237     if((ret < min) || (ret > max))
238     {
239         ErrorExit(INV_DEF, __local_name, high_name, low_name, value);
240     }
241
242     /* Clearing memory */
243     free(value);
244
245     return(ret);
246 }
247
248
249 /** int OS_IPFound(char *ip_address, os_ip *that_ip)
250  * Checks if ip_address is present at that_ip.
251  * Returns 1 on success or 0 on failure.
252  */
253 int OS_IPFound(char *ip_address, os_ip *that_ip)
254 {
255     int _true = 1;
256     struct in_addr net;
257
258     /* Extracting ip address */
259     if((net.s_addr = inet_addr(ip_address)) <= 0)
260     {
261         return(!_true);
262     }
263                                 
264     /* If negate is set */
265     if(that_ip->ip[0] == '!')
266     {
267         _true = 0;
268     }
269     
270     /* Checking if ip is in thatip & netmask */
271     if((net.s_addr & that_ip->netmask) == that_ip->ip_address)
272     {
273         return(_true);
274     }
275
276     /* Didn't match */
277     return(!_true);
278 }
279
280      
281 /** int OS_IPFoundList(char *ip_address, os_ip **list_of_ips)
282  * Checks if ip_address is present on the "list_of_ips".
283  * Returns 1 on success or 0 on failure.
284  * The list MUST be NULL terminated
285  */
286 int OS_IPFoundList(char *ip_address, os_ip **list_of_ips)
287 {
288     struct in_addr net;
289     int _true = 1;
290
291     /* Extracting ip address */
292     if((net.s_addr = inet_addr(ip_address)) <= 0)
293     {
294         return(!_true);
295     }
296                                         
297     while(*list_of_ips)
298     {
299         os_ip *l_ip = *list_of_ips;
300         
301         if(l_ip->ip[0] == '!')
302         {
303             _true = 0;
304         }
305     
306         if((net.s_addr & l_ip->netmask) == l_ip->ip_address)
307         {
308             return(_true);
309         }
310         list_of_ips++;
311     }
312
313     return(!_true);
314 }    
315
316      
317 /** int OS_IsValidIP(char *ip)
318  * Validates if an ip address is in the right
319  * format.
320  * Returns 0 if doesn't match or 1 if it is an ip or 2 an ip with cidr.
321  * ** On success this function may modify the value of ip_address
322  */
323 int OS_IsValidIP(char *ip_address, os_ip *final_ip)
324 {
325     unsigned int nmask = 0;
326     char *tmp_str;
327
328     /* Can't be null */
329     if(!ip_address)
330     {
331         return(0);
332     }
333
334     /* Assigning the ip address */
335     if(final_ip)
336     {
337         os_strdup(ip_address, final_ip->ip);
338     }
339     
340     if(*ip_address == '!')
341     {
342         ip_address++;
343     }
344    
345     #ifndef WIN32 
346     /* checking against the basic regex */
347     if(!OS_PRegex(ip_address, ip_address_regex))
348     {
349         if(strcmp(ip_address, "any") != 0)
350         {
351             return(0);
352         }
353     }
354     #else
355
356     if(strcmp(ip_address, "any") != 0)
357     {
358         char *tmp_ip;
359         int dots = 0;
360         tmp_ip = ip_address;
361         while(*tmp_ip != '\0')
362         {
363             if((*tmp_ip < '0' || 
364                *tmp_ip > '9') &&   
365                *tmp_ip != '.' &&
366                *tmp_ip != '/')
367             {
368                 /* Invalid ip */
369                 return(0);
370             }
371             if(*tmp_ip == '.')
372                 dots++;
373             tmp_ip++;
374         }
375         if(dots < 3 || dots > 6)
376             return(0);
377     }
378     #endif
379
380
381
382     /* Getting the cidr/netmask if available */ 
383     tmp_str = strchr(ip_address,'/');
384     if(tmp_str)
385     {
386         int cidr;
387         struct in_addr net;
388         
389         *tmp_str = '\0';
390         tmp_str++;
391
392         /* Cidr */
393         if(strlen(tmp_str) <= 2)
394         {
395             cidr = atoi(tmp_str);
396             if((cidr >= 0) && (cidr <= 32))
397             {
398                 if(!_mask_inited)
399                     _init_masks();
400                 nmask = _netmasks[cidr];
401                 nmask = htonl(nmask);
402             }
403             else
404             {
405                 return(0);
406             }
407         }
408         /* Full netmask */
409         else
410         {
411             /* Init the masks */
412             if(!_mask_inited)
413                 _init_masks();
414
415             if(strcmp(tmp_str, "255.255.255.255") == 0)
416             {
417                 nmask = htonl(_netmasks[32]);
418             }
419             else
420             {
421                 if((nmask = inet_addr(ip_address)) <= 0)
422                 {
423                     return(0);
424                 }
425             }
426         }
427         
428         if((net.s_addr = inet_addr(ip_address)) <= 0)
429         {
430             if(strcmp("0.0.0.0", ip_address) == 0)
431             {
432                 net.s_addr = 0;
433             }
434             else
435             {
436                 return(0);
437             }
438         }
439
440         if(final_ip)
441         {
442             final_ip->ip_address = net.s_addr & nmask;
443             final_ip->netmask = nmask;
444         }
445
446         tmp_str--;
447         *tmp_str = '/';
448
449         return(2);
450     }
451
452     /* No cidr available */
453     else
454     {
455         struct in_addr net;
456         nmask = 32;
457         
458         if(strcmp("any", ip_address) == 0)
459         {
460             net.s_addr = 0;
461             nmask = 0;
462         }
463         else if((net.s_addr = inet_addr(ip_address)) <= 0)
464         {
465             return(0);
466         }
467         
468         if(final_ip)
469         {
470             final_ip->ip_address = net.s_addr;
471
472             if(!_mask_inited)
473                 _init_masks();
474         
475             final_ip->netmask = htonl(_netmasks[nmask]);
476         }
477
478         /* Ip without cidr */
479         if(nmask)
480         {
481             return(1);
482         }
483
484         return(2);
485     }
486
487     /* Should never reach here */
488     return(0);
489 }
490
491
492 /** int OS_IsonTime(char *time_str, char *ossec_time)
493  * Must be a valid string, called after OS_IsValidTime.
494  * Returns 1 on success or 0 on failure.
495  */
496 int OS_IsonTime(char *time_str, char *ossec_time)
497 {
498     int _true = 1;
499
500     if(*ossec_time == '!')
501     {
502         _true = 0;
503     }
504     ossec_time++;
505
506     /* Comparing against min/max value */
507     if((strncmp(time_str, ossec_time, 5) >= 0)&&
508       (strncmp(time_str, ossec_time+5,5) <= 0))  
509     {
510         return(_true);
511     }
512     
513     return(!_true);
514 }
515
516
517 /** char *OS_IsValidTime(char *time_str)
518  * Validates if a time is in an acceptable format
519  * for ossec.
520  * Returns 0 if doesn't match or a valid string for
521  * ossec usage in success.
522  * ** On success this function may modify the value of date
523  * Acceptable formats:
524  * hh:mm - hh:mm (24 hour format)
525  * !hh:mm -hh:mm (24 hour format)
526  * hh - hh (24 hour format)
527  * hh:mm am - hh:mm pm (12 hour format)
528  * hh am - hh pm (12 hour format)
529  */
530 #define RM_WHITE(x)while(*x == ' ')x++;
531 char *__gethour(char *str, char *ossec_hour)
532 {
533     int _size = 0;
534     int chour = 0;
535     int cmin = 0;
536     
537     /* Invalid time format */
538     if(!isdigit((int)*str))
539     {
540         merror(INVALID_TIME, __local_name, str);
541     }
542     
543
544     /* Hour */
545     chour = atoi(str);
546
547
548     /* Getting a valid hour */
549     if(chour < 0 || chour >= 24)
550     {
551         merror(INVALID_TIME, __local_name, str);
552         return(NULL);
553
554     }
555     
556     /* Going after the hour */
557     while(isdigit((int)*str))
558     {
559         _size++;
560         str++;
561     }
562
563     /* Invalid hour */
564     if(_size > 2)
565     {
566         merror(INVALID_TIME, __local_name, str);
567         return(NULL);
568     }
569     
570     
571     /* Getting minute */
572     if(*str == ':')
573     {
574         str++;
575         if((!isdigit((int)*str)||
576             !isdigit((int)*(str +1))) && isdigit((int)*(str +2)))
577         {
578             merror(INVALID_TIME, __local_name, str);
579             return(NULL);
580         }
581
582         cmin = atoi(str);
583         str+=2;
584     }
585
586     /* Removing spaces */
587     RM_WHITE(str);
588     
589     if((*str == 'a') || (*str == 'A'))
590     {
591         str++;
592         if((*str == 'm') || (*str == 'M'))
593         {
594             snprintf(ossec_hour, 6, "%02d:%02d", chour, cmin);
595             str++;
596             return(str);
597         }
598     }
599     else if((*str == 'p') || (*str == 'P'))
600     {
601         str++;
602         if((*str == 'm') || (*str == 'M'))
603         {
604             chour += 12;
605             
606             /* New hour must be valid */
607             if(chour < 0 || chour >= 24)
608             {
609                 merror(INVALID_TIME, __local_name, str);
610                 return(NULL);
611             }
612                                                 
613             snprintf(ossec_hour, 6, "%02d:%02d", chour, cmin);
614             str++;
615             return(str);
616         }
617         
618     }
619     else
620     {
621         snprintf(ossec_hour, 6, "%02d:%02d", chour, cmin);
622         return(str);
623     }
624
625     /* Here is error */
626     merror(INVALID_TIME, __local_name, str);
627     return(NULL);
628 }
629
630
631 char *OS_IsValidTime(char *time_str)
632 {
633     char *ret;
634     char first_hour[7];
635     char second_hour[7];
636     int ng = 0;
637     
638     /* Must be not null */
639     if(!time_str)
640         return(NULL);
641     
642         
643     /* Clearing memory */
644     memset(first_hour, '\0', 7);
645     memset(second_hour, '\0', 7);
646     
647     
648     /* Removing white spaces */
649     RM_WHITE(time_str);
650
651
652     /* Checking for negative */
653     if(*time_str == '!')
654     {
655         ng = 1;
656         time_str++;
657
658         /* We may have white spaces after the '!' */
659         RM_WHITE(time_str);
660     }
661
662     
663     /* Getting first hour */
664     time_str = __gethour(time_str, first_hour);
665     if(!time_str)
666         return(NULL);
667
668     /* Removing white spaces */
669     RM_WHITE(time_str);
670     
671     if(*time_str != '-')
672     {
673         return(NULL);
674     }
675
676     time_str++;
677
678     /* Removing white spaces */
679     RM_WHITE(time_str);
680
681     /* Getting second hour */
682     time_str = __gethour(time_str, second_hour);
683     if(!time_str)
684         return(NULL);
685     
686     RM_WHITE(time_str);
687     if(*time_str != '\0')
688     {
689         return(NULL);
690     }
691
692     os_calloc(13, sizeof(char), ret);
693     
694     /* Fixing dump hours */
695     if(strcmp(first_hour,second_hour) > 0)
696     {
697         snprintf(ret, 12, "!%s%s", second_hour, first_hour);
698         return(ret);
699     }
700     
701     /* For the normal times */
702     snprintf(ret, 12, "%c%s%s", ng == 0?'.':'!', first_hour, second_hour);
703     return(ret);
704 }
705
706
707
708 /** int OS_IsAfterTime(char *time_str, char *ossec_time)
709  *  Checks if the current time is the same or has passed the
710  *  specified one.
711  */
712 int OS_IsAfterTime(char *time_str, char *ossec_time)
713 {
714     /* Unique times can't have a !. */
715     if(*ossec_time == '!')
716         return(0);
717     
718         
719     ossec_time++;
720
721     /* Comparing against min/max value */
722     if(strncmp(time_str, ossec_time, 5) >= 0)
723     {
724         return(1);
725     }
726
727     return(0);
728 }
729
730
731
732 /** char *OS_IsValidUniqueTime(char *time_str)
733  *  Creates a unique time, not a range. Must be used with OS_IsAfterTime.
734  */
735 char *OS_IsValidUniqueTime(char *time_str)
736 {
737     char mytime[128 +1];
738
739     if(*time_str == '!')
740         return(NULL);
741
742     memset(mytime, '\0', 128 +1);
743     snprintf(mytime, 128, "%s-%s", time_str, time_str);
744
745
746     return(OS_IsValidTime(mytime));
747 }
748
749
750
751 /** int OS_IsonDay(int week_day, char *ossec_day)
752  * Checks if the specified week day is in the
753  * range.
754  */
755 int OS_IsonDay(int week_day, char *ossec_day)
756 {
757     int _true = 1;
758
759     /* Negative */
760     if(ossec_day[7] == '!')
761         _true = 0;
762     
763     if(week_day < 0 || week_day > 7)
764     {
765         return(0);
766     }
767
768     /* It is on the right day */
769     if(ossec_day[week_day] == 1)
770         return(_true);
771     
772     return(!_true);    
773 }
774
775
776
777 /** char *OS_IsValidDay(char *day_str)
778  * Validates if an day is in an acceptable format
779  * for ossec.
780  * Returns 0 if doesn't match or a valid string for
781  * ossec usage in success.
782  * ** On success this function may modify the value of date
783  * Acceptable formats:
784  * weekdays, weekends, monday, tuesday, thursday,..
785  * monday,tuesday
786  * mon,tue wed
787  */
788 #define RM_SEP(x)while((*x == ' ') || (*x == ','))x++;
789 #define IS_SEP(x) (*x == ' ' || *x == ',')
790 char *OS_IsValidDay(char *day_str)
791 {
792     int i = 0, ng = 0;
793     char *ret;
794     char day_ret[9] = {0,0,0,0,0,0,0,0,0};
795     char *(days[]) = 
796     {
797         "sunday", "sun", "monday", "mon", "tuesday", "tue",
798         "wednesday", "wed", "thursday", "thu", "friday",
799         "fri", "saturday", "sat", "weekdays", "weekends", NULL
800     };
801     int days_int[] = {0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,8};
802
803     /* Must be a valid string */
804     if(!day_str)
805         return(NULL);
806     
807     
808     RM_WHITE(day_str);
809     
810     /* checking for negatives */
811     if(*day_str == '!')
812     {
813         ng = 1;
814         RM_WHITE(day_str);
815     }
816
817     while(*day_str != '\0')
818     {
819         i = 0;
820         while(days[i])
821         {
822             if(strncasecmp(day_str, days[i], strlen(days[i])) == 0)
823             {
824                 /* Weekdays */
825                 if(days_int[i] == 7)
826                 {
827                     day_ret[1] = 1;
828                     day_ret[2] = 1;
829                     day_ret[3] = 1;
830                     day_ret[4] = 1;
831                     day_ret[5] = 1;
832                 }
833                 /* weekends */
834                 else if(days_int[i] == 8)
835                 {
836                     day_ret[0] = 1;
837                     day_ret[6] = 1;
838                 }
839                 else
840                 {
841                     day_ret[days_int[i]] = 1;
842                 }
843                 break;
844             }
845             i++;
846         }
847
848         if(!days[i])
849         {
850             merror(INVALID_DAY, __local_name, day_str);
851             return(NULL);
852         }
853         
854         day_str += strlen(days[i]);
855
856         if(IS_SEP(day_str))
857         {
858             RM_SEP(day_str);
859             continue;
860         }
861         else if(*day_str == '\0')
862             break;
863         else
864         {
865             merror(INVALID_DAY, __local_name, day_str);
866             return(NULL);
867         }
868     }
869
870     /* Assigning values */
871     os_calloc(9, sizeof(char), ret);
872     if(ng == 1)
873     {
874         /* Setting nevative */
875         ret[7] = '!';
876     }
877
878     ng = 0;
879     for(i = 0;i<=6;i++)
880     {
881         /* Checking if some is checked */
882         if(day_ret[i] == 1)
883             ng = 1;
884         ret[i] = day_ret[i];
885     }
886
887     /* At least one day must be checked */
888     if(ng == 0)
889     {
890         free(ret);
891         merror(INVALID_DAY, __local_name, day_str);
892         return(NULL);
893     }
894     
895     return(ret);
896 }
897
898 /* EOF */