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