/*
 *   logtool - a logfile parsing/monitoring/manipulation utility
 *
 *   Copyright (C) Y2K (2000) A.L.Lambert
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2, or (at your option)
 *   any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* yee ole' includes */
#include "includes.h"


/* A regex function to match paterns */
int lt_match(const char *string, char *pattern) /* This means "what you want to search", "what you want to search for" */
{
	int    status;
	regex_t    re;

        if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0) {
		return(FALSE);      /* report error */
         } 
         status = regexec(&re, string, (size_t) 0, NULL, 0);
         regfree(&re);
         if (status != 0) {
             return(FALSE);      /* report error */
         }
         return(TRUE);
}

/* a function to match against pre-compiled regex's	*/
int lt_match_re(const char *string, regex_t re) {
	int status;
	status = regexec(&re, string, (size_t) 0, NULL, 0);
	if (status != 0) {
		return FALSE;
	} else {
		return TRUE;
	}

}

int lt_filelen(FILE *file) {
	int retval = 0;
	/* find out how long the file is	*/
	fseek(file, 0, SEEK_END);	/* seek end of file	*/
	retval = ftell(file);		/* get byte value	*/
	fseek(file, 0, SEEK_SET);	/* return to begin	*/
	return retval;			/* return size of file	*/
}

short int lt_load_regex(char *file, char **dest, regex_t *re) {
	char line[LSIZE];
	char tmp[LSIZE];
	char count = 1;
	FILE *fileptr;
	short int retval;
	DIR *dir;
	struct stat *stbuf;
	char *fname;
	struct dirent *de;

	stbuf=malloc(sizeof(struct stat));
	if(stat(file, stbuf)<0) {
		/* Could not stat, so, back out */
		if(cf.debug) fprintf(stderr, "Could not stat %s\n", file);
		return FALSE;
	}

	if(S_ISDIR(stbuf->st_mode)) {
		dir=opendir(file);
		if( ! dir ) {
			if(cf.debug) fprintf(stderr, "Could not opendir %s\n", file);
			return FALSE;
		}
		while((de=readdir(dir))) {
			if(!strncmp(de->d_name, ".", 1)) continue;
			fname=malloc(strlen(file)+strlen(de->d_name)+2);
			sprintf(fname, "%s/%s", file, de->d_name);
			if(!lt_load_regex(fname, dest, re)) {
				if(cf.debug) fprintf(stderr,
						"error occured, bailing out\n");
				free(fname);
				return FALSE;
			}
			free(fname);
		}
		return TRUE;
	}

        fileptr = fopen(file, "r");
        if( ! fileptr ) {
		if(cf.debug) fprintf(stderr, "unable to open file: %s\n", file);
		/* oopsie; no such file; abort this loading, and return FALSE	*/
		return FALSE;
	}
	
	/* we malloc enough space for 2 of these files just to be safe we don't 
	 * overflow as we add |'s and such to build the regexec string */
	*dest = malloc(lt_filelen(fileptr) * 2);
	*dest[0] = '\0';
	
	/* while we read the file, and don't have comments	*/
	while(fgets(line, LSIZE, fileptr) != NULL) {
		if(lt_match(line, "^#|^$") == 0) {
			sscanf(line, "%[^\n]", tmp);
			if(count == 1) {
				strncat(*dest, tmp, strlen(tmp) + 1);
				count = 2;
			} else {
				strncat(*dest, "|", 2);
				strncat(*dest, tmp, strlen(tmp) + 1);
			}
		}
	}
	
	/* close off yee ole file pointer	*/
	fclose(fileptr);

	/* if we got no valid regex's, then return false	*/
	if(*dest[0] == '\0') {
		/* we had no strings, nevermind			*/
		retval = FALSE;
	} else {
		retval = TRUE;	/* assume those strings are valid	*/
		/* see if we can compile the patern into a regex	*/
		if (regcomp(re, *dest, REG_EXTENDED|REG_NOSUB) != 0) {
			/* oops; wouldn't compile.. nevermind		*/
			return(FALSE);      /* report error */
		}
	}
	        
	if(cf.debug) fprintf(stderr, "opened file: %s and got strings >%s<\n", file, *dest);	
	return (retval);
}


void lt_loadstrings() {
	/* for all the regex's we want to load, hit em up here		*/
	/* if you're adding one of these, see logtool.h, readconf.c and regex.c */

	/* I need to get off my butt and init this in lt_set_regfile() in readconf.c instead of here, :)	*/
	
	reg.include_check = 	lt_load_regex(reg.include_file, &reg.include_strs, &reg.include_reg);
	reg.exclude_check = 	lt_load_regex(reg.exclude_file, &reg.exclude_strs, &reg.exclude_reg);
	
	reg.green_check = 	lt_load_regex(reg.green_file, &reg.green_strs, &reg.green_reg);
	reg.brightgreen_check =	lt_load_regex(reg.brightgreen_file, &reg.brightgreen_strs, &reg.brightgreen_reg);
	reg.yellow_check = 	lt_load_regex(reg.yellow_file, &reg.yellow_strs, &reg.yellow_reg);
	reg.brightyellow_check =lt_load_regex(reg.brightyellow_file, &reg.brightyellow_strs, &reg.brightyellow_reg);
	reg.blue_check = 	lt_load_regex(reg.blue_file, &reg.blue_strs, &reg.blue_reg);
	reg.brightblue_check = 	lt_load_regex(reg.brightblue_file, &reg.brightblue_strs, &reg.brightblue_reg);
	reg.cyan_check = 	lt_load_regex(reg.cyan_file, &reg.cyan_strs, &reg.cyan_reg);
	reg.brightcyan_check = 	lt_load_regex(reg.brightcyan_file, &reg.brightcyan_strs, &reg.brightcyan_reg);
	reg.magenta_check = 	lt_load_regex(reg.magenta_file, &reg.magenta_strs, &reg.magenta_reg);
	reg.brightmagenta_check =	lt_load_regex(reg.brightmagenta_file, &reg.brightmagenta_strs, &reg.brightmagenta_reg);
	reg.brightred_check =	lt_load_regex(reg.brightred_file, &reg.brightred_strs, &reg.brightred_reg);
}



/* our different event types defined: for EVENT_*.  They are (currently) SYSLOG, SNORT, and IPTABLES	*/
/* Laurent Jacquot: I have got some lines not matching ^[A-Z] ... 					*/
char syslog_format[256] =	"^[A-Za-z][a-z][a-z] .[0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] .* .* .*$";
char snort_format[256] =	"^[A-Za-z][a-z][a-z] .[0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] .* snort.*: .*[0-9] -> .*[0-9].*$";
char iptables_format[256] =	"^[A-Za-z][a-z][a-z] .[0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] .*IN=.* OUT=.* SRC=.* DST=.* .*$";

regex_t syslog_freg;
regex_t snort_freg;
regex_t iptables_freg;

void lt_regexinit() {
	regcomp(&syslog_freg, syslog_format, REG_EXTENDED|REG_NOSUB);
	regcomp(&snort_freg, snort_format, REG_EXTENDED|REG_NOSUB);
	regcomp(&iptables_freg, iptables_format, REG_EXTENDED|REG_NOSUB);
	lt_loadstrings();
}


/* currently known event types: SNORT SYSLOG UNKNOWN	*/
short int lt_fmtcheck(char *tmp) {
	short int retval = -1;

	if(lt_match_re(tmp, syslog_freg) == TRUE) {
		retval = EVENT_SYSLOG;
	}
       	if(lt_match_re(tmp, snort_freg) == TRUE) {
		retval = EVENT_SNORT;
	}
	if(lt_match_re(tmp, iptables_freg) == TRUE) {
		retval = EVENT_IPTABLES;
	}

	if(retval == -1) {
		retval = EVENT_UNKNOWN;
	}
	
	return retval;
}
