###############################################################################
# Guardian.pl                                                                 #
###############################################################################
# YaBB: Yet another Bulletin Board                                            #
# Open-Source Community Software for Webmasters                               #
# Version:        YaBB 2 RC 3                                                 #
# Released:       June 20, 2005                                               #
# Distributed by: http://www.yabbforum.com                                    #
# =========================================================================== #
# Copyright (c) 2000-2005 YaBB (www.yabbforum.com) - All Rights Reserved.     #
# Software by: The YaBB Development Team                                      #
#              with assistance from the YaBB community.                       #
# Sponsored by: Xnull Internet Media, Inc. - http://www.ximinc.com            #
#               Your source for web hosting, web design, and domains.         #
###############################################################################

$guardianplver = 'YaBB 2 RC 3 $Revision: 1.20 $';
if($action eq 'detailedversion') { return 1; }

&LoadLanguage("Guardian");
require "$vardir/Guardian.settings";
require "$vardir/Guardian.banned";
$not_from = qq~$webmaster_email~;
$not_to = qq~$webmaster_email~;
$abuse_time = &timeformat($date);
$abuse_time =~s/\<sup\>\*\<\/sup\>/\*/g;

sub guard {
	if(!$use_guardian){return;}
	## Proxy Blocker
	$proxy0 = &get_remote_addr;
	$proxy1 = &get_x_ip_client;
	$proxy2 = &get_x_forwarded;
	$proxy3 = &get_http_via;

	@white_list = split(/\|/,$whitelist);
	foreach (@white_list) {
		chomp $_;
 		if (($proxy0 =~ m/$_/ || $proxy1 =~ m/$_/ || $proxy2 =~ m/$_/ || $proxy3 =~ m/$_/ || $username eq $_) && $_ ne "") { $whitelisted = 1; last;}
	}
	if($disallow_proxy_on && !$whitelisted && !$iamadmin && ($proxy1 ne "empty" || $proxy2 ne "empty" || $proxy3 ne "empty")) {
		if($disallow_proxy_notify){
			$not_subject = qq~$guardian_txt{'main'}-($mbname): $guardian_txt{'proxy_abuse'} $guardian_txt{'abuse'}~;
			$not_body = qq~$guardian_txt{'proxy_abuse'} $guardian_txt{'abuse'} $maintxt{'30'} $abuse_time\n\n~;
			$not_body .= qq~$guardian_txt{'abuse_user'}: $username -> ($realname)\n~;
			$not_body .= qq~$guardian_txt{'abuse_ip'}: (REMOTE_ADDR)->$proxy0, (X_IP_CLIENT)->$proxy1, (HTTP_X_FORWARDED_FOR)->$proxy2, (HTTP_VIA)->$proxy3\n~;
			if($use_htaccess && $disallow_proxy_htaccess && !$iamadmin && !$iamgmod){
				$not_body .= qq~$guardian_txt{'htaccess_added'}: $user_ip,\n\n~;
			}
			$not_body .= qq~$mbname, $guardian_txt{'main'}~;
			$not_subject =~ s~\&trade\;~~g;
			$not_body =~ s~\&trade\;~~g;
			&guardian_notify($not_to,$not_subject,$not_body,$not_from);
		}
		if($use_htaccess && $disallow_proxy_htaccess && !$iamadmin && !$iamgmod){
			&update_htaccess("add",$user_ip);
		}
		&fatal_error("$guardian_txt{'proxy_reason'}");
	}
	
	## Basic Value Setup
	$remote = &get_ip;
	if (index($remote, ", ")) {
		@remotes = split("\, ", $remote);
		if($remotes[0] ne "unknown" && $remotes[0] ne "empty" && $remotes[0] ne "127.0.0.1" && $remotes[0] ne "") {
			$remote = $remotes[0];
		} else {
			$remote = $remotes[1];
		}
	}
	$querystring = &get_query_string;
	
	## Check for Referer
	if($referer_on) {
		@refererlist = split(/\|/,$banned_referers);
		$streferer = &get_referer;
		foreach (@refererlist) {
			chomp $_;
			if ($streferer=~ m/$_/ && $_ ne "") {
				if($referer_notify){
					$not_subject = qq~$guardian_txt{'main'}-($mbname): $guardian_txt{'referer_abuse'} $guardian_txt{'abuse'}~;
					$not_body = qq~$guardian_txt{'referer_abuse'} $guardian_txt{'abuse'} $maintxt{'30'} $abuse_time\n\n~;
					$not_body .= qq~$guardian_txt{'abuse_user'}: $username -> ($realname)\n~;
					$not_body .= qq~$guardian_txt{'abuse_ip'}: $user_ip\n~;
					if($use_htaccess && $referer_htaccess && !$iamadmin && !$iamgmod){
						$not_body .= qq~$guardian_txt{'htaccess_added'}: $user_ip,\n~;
					}
					$not_body .= qq~$guardian_txt{'abuse_referer'}: $streferer\n\n~;
					$not_body .= qq~$mbname, $guardian_txt{'main'}~;
					$not_subject =~ s~\&trade\;~~g;
					$not_body =~ s~\&trade\;~~g;
					&guardian_notify($not_to,$not_subject,$not_body,$not_from);
				}
				if($use_htaccess && $referer_htaccess && !$iamadmin && !$iamgmod){
					&update_htaccess("add",$user_ip);
				}
				&fatal_error("$guardian_txt{'referer_reason'}");
			}
		}
	}
	
	## Check for Harvester
	if($harvester_on) {
		@harvesterlist = split(/\|/,$banned_harvesters);
		$agent = &get_user_agent;
		foreach (@harvesterlist) {
			chomp $_;
			if ($agent=~ m/$_/ && $_ ne "") {
				if($harvester_notify){
					$not_subject = qq~$guardian_txt{'main'}-($mbname): $guardian_txt{'harvester_abuse'} $guardian_txt{'abuse'}~;
					$not_body = qq~$guardian_txt{'harvester_abuse'} $guardian_txt{'abuse'} $maintxt{'30'} $abuse_time\n\n~;
					$not_body .= qq~$guardian_txt{'abuse_user'}: $username -> ($realname)\n~;
					$not_body .= qq~$guardian_txt{'abuse_ip'}: $user_ip\n~;
					if($use_htaccess && $harvester_htaccess && !$iamadmin && !$iamgmod){
						$not_body .= qq~$guardian_txt{'htaccess_added'}: $user_ip,\n~;
					}
					$not_body .= qq~$guardian_txt{'abuse_harvester'}: $agent\n\n~;
					$not_body .= qq~$mbname, $guardian_txt{'main'}~;
					&guardian_notify($not_to,$not_subject,$not_body,$not_from);
				}
				if($use_htaccess && $harvester_htaccess && !$iamadmin && !$iamgmod){
					&update_htaccess("add",$user_ip);
				}
				&fatal_error("$guardian_txt{'harvester_reason'}");
			}
		}
	}
	
	## Check for Request
	if($request_on) {
		@requestlist = split(/\|/,$banned_requests);
		$method = &get_request_method;
		foreach (@requestlist) {
			chomp $_;
			if ($method=~ m/$_/ && $_ ne "") {
				if($request_notify){
					$not_subject = qq~$guardian_txt{'main'}-($mbname): $guardian_txt{'request_abuse'} $guardian_txt{'abuse'}~;
					$not_body = qq~$guardian_txt{'request_abuse'} $guardian_txt{'abuse'} $maintxt{'30'} $abuse_time\n\n~;
					$not_body .= qq~$guardian_txt{'abuse_user'}: $username -> ($realname)\n~;
					$not_body .= qq~$guardian_txt{'abuse_ip'}: $user_ip\n~;
					if($use_htaccess && $request_htaccess && !$iamadmin && !$iamgmod){
						$not_body .= qq~$guardian_txt{'htaccess_added'}: $user_ip,\n~;
					}
					$not_body .= qq~$guardian_txt{'abuse_request'}: $method\n\n~;
					$not_body .= qq~$mbname, $guardian_txt{'main'}~;
					$not_subject =~ s~\&trade\;~~g;
					$not_body =~ s~\&trade\;~~g;
					&guardian_notify($not_to,$not_subject,$not_body,$not_from);
				}
				if($use_htaccess && $request_htaccess && !$iamadmin && !$iamgmod){
					&update_htaccess("add",$user_ip);
				}
				&fatal_error("$guardian_txt{'request_reason'}");
			}
		}
	}
	
	## Check for Strings
	if($string_on) {
		@stringlist = split(/\|/,$banned_strings);
		foreach (@stringlist) {
			chomp $_;
			if ($querystring =~ m/$_/ && $_ ne "") {
				if($string_notify){
					$not_subject = qq~$guardian_txt{'main'}-($mbname): $guardian_txt{'string_abuse'} $guardian_txt{'abuse'}~;
					$not_body = qq~$guardian_txt{'string_abuse'} $guardian_txt{'abuse'} $maintxt{'30'} $abuse_time\n\n~;
					$not_body .= qq~$guardian_txt{'abuse_user'}: $username -> ($realname)\n~;
					$not_body .= qq~$guardian_txt{'abuse_ip'}: $user_ip\n~;
					if($use_htaccess && $string_htaccess && !$iamadmin && !$iamgmod){
						$not_body .= qq~$guardian_txt{'htaccess_added'}: $user_ip,\n~;
					}
					$not_body .= qq~$guardian_txt{'abuse_string'}: $_\n~;
					$not_body .= qq~$guardian_txt{'abuse_environment'}: $querystring\n\n~;
					$not_body .= qq~$mbname, $guardian_txt{'main'}~;
					$not_subject =~ s~\&trade\;~~g;
					$not_body =~ s~\&trade\;~~g;
					&guardian_notify($not_to,$not_subject,$not_body,$not_from);
				}
				if($use_htaccess && $string_htaccess && !$iamadmin && !$iamgmod){
					&update_htaccess("add",$user_ip);
				}
				&fatal_error("$guardian_txt{'string_reason'} ($_)");
			}
		}
	}
	
	## Check for UNION attack (for MySQL database protection only)
	if($union_on) {
		if ($querystring =~ m/%20union%20/ || $querystring =~ m/\*\/union\/\*/) {
			if($union_notify){
				$not_subject = qq~$guardian_txt{'main'}-($mbname): $guardian_txt{'union_abuse'} $guardian_txt{'abuse'}~;
				$not_body = qq~$guardian_txt{'union_abuse'} $guardian_txt{'abuse'} $maintxt{'30'} $abuse_time\n\n~;
				$not_body .= qq~$guardian_txt{'abuse_user'}: $username -> ($realname)\n~;
				$not_body .= qq~$guardian_txt{'abuse_ip'}: $user_ip\n~;
				if($use_htaccess && $union_htaccess && !$iamadmin && !$iamgmod){
					$not_body .= qq~$guardian_txt{'htaccess_added'}: $user_ip,\n~;
				}
				$not_body .= qq~$guardian_txt{'abuse_environment'}: $querystring\n\n~;
				$not_body .= qq~$mbname, $guardian_txt{'main'}~;
				$not_subject =~ s~\&trade\;~~g;
				$not_body =~ s~\&trade\;~~g;
				&guardian_notify($not_to,$not_subject,$not_body,$not_from);
			}
			if($use_htaccess && $union_htaccess && !$iamadmin && !$iamgmod){
				&update_htaccess("add",$user_ip);
			}
			&fatal_error($guardian_txt{'union_reason'});
		}
	}
	
	## Check for CLIKE attack (for MySQL database protection only)
	if($clike_on) {
		if ($querystring =~ m/\/\*/) {
			if($clike_notify){
				$not_subject = qq~$guardian_txt{'main'}-($mbname): $guardian_txt{'clike_abuse'} $guardian_txt{'abuse'}~;
				$not_body = qq~$guardian_txt{'clike_abuse'} $guardian_txt{'abuse'} $maintxt{'30'} $abuse_time\n\n~;
				$not_body .= qq~$guardian_txt{'abuse_user'}: $username -> ($realname)\n~;
				$not_body .= qq~$guardian_txt{'abuse_ip'}: $user_ip\n~;
				if($use_htaccess && $clike_htaccess && !$iamadmin && !$iamgmod){
					$not_body .= qq~$guardian_txt{'htaccess_added'}: $user_ip,\n~;
				}
				$not_body .= qq~$guardian_txt{'abuse_environment'}: $querystring\n\n~;
				$not_body .= qq~$mbname, $guardian_txt{'main'}~;
				$not_subject =~ s~\&trade\;~~g;
				$not_body =~ s~\&trade\;~~g;
				&guardian_notify($not_to,$not_subject,$not_body,$not_from);
			}
			if($use_htaccess && $clike_htaccess && !$iamadmin && !$iamgmod){
				&update_htaccess("add",$user_ip);
			}
			&fatal_error($guardian_txt{'clike_reason'});
		}
	}
	
	## Check for SCRIPTING attack
	# Removed $iamadmin check - so it protects EVERYONE.
	if($script_on) {
		while( ($key,$secvalue) = each(%INFO) ) {
			$secvalue = lc($secvalue);
			&str_replace("%3c", "<", $secvalue);
			&str_replace("%3e", ">", $secvalue);
			if (($secvalue =~ m/<[^>]script*\"?[^>]*>/) || ($secvalue =~ m/<[^>]*object*\"?[^>]*>/) || ($secvalue =~ m/<[^>]*iframe*\"?[^>]*>/) || ($secvalue =~ m/<[^>]*applet*\"?[^>]*>/) || ($secvalue =~ m/<[^>]*meta*\"?[^>]*>/) || ($secvalue =~ m/<[^>]*style*\"?[^>]*>/) || ($secvalue =~ m/<[^>]*form*\"?[^>]*>/) || ($secvalue =~ m/\([^>]*\"?[^)]*\)/) || ($secvalue =~ m/\"/)) {
				if($script_notify){
					$not_subject = qq~$guardian_txt{'main'}-($mbname): $guardian_txt{'script_abuse'} $guardian_txt{'abuse'}~;
					$not_body = qq~$guardian_txt{'script_abuse'} $guardian_txt{'abuse'} $maintxt{'30'} $abuse_time\n\n~;
					$not_body .= qq~$guardian_txt{'abuse_user'}: $username -> ($realname)\n~;
					$not_body .= qq~$guardian_txt{'abuse_ip'}: $user_ip\n~;
					if($use_htaccess && $script_htaccess && !$iamadmin && !$iamgmod){
						$not_body .= qq~$guardian_txt{'htaccess_added'}: $user_ip,\n~;
					}
					$not_body .= qq~$guardian_txt{'abuse_url_environment'}: $secvalue\n\n~;
					$not_body .= qq~$mbname, $guardian_txt{'main'}~;
					$not_subject =~ s~\&trade\;~~g;
					$not_body =~ s~\&trade\;~~g;
					&guardian_notify($not_to,$not_subject,$not_body,$not_from);
				}
				if($use_htaccess && $script_htaccess && !$iamadmin && !$iamgmod){
					&update_htaccess("add",$user_ip);
				}
				&fatal_error($guardian_txt{'script_reason'});
			}
		}
		while( ($key,$secvalue) = each(%FORM) ) {
			$secvalue = lc($secvalue);
			&str_replace("%3c", "<", $secvalue);
			&str_replace("%3e", ">", $secvalue);
			if (($secvalue =~ m/<[^>]script*\"?[^>]*>/) || ($secvalue =~ m/<[^>]style*\"?[^>]*>/)) {
				if($script_notify){
					$not_subject = qq~$guardian_txt{'main'}-($mbname): $guardian_txt{'script_abuse'} $guardian_txt{'abuse'}~;
					$not_body = qq~$guardian_txt{'script_abuse'} $guardian_txt{'abuse'} $maintxt{'30'} $abuse_time\n\n~;
					$not_body .= qq~$guardian_txt{'abuse_user'}: $username -> ($realname)\n~;
					$not_body .= qq~$guardian_txt{'abuse_ip'}: $user_ip\n~;
					if($use_htaccess && $script_htaccess && !$iamadmin && !$iamgmod){
						$not_body .= qq~$guardian_txt{'htaccess_added'}: $user_ip,\n~;
					}
					$not_body .= qq~$guardian_txt{'abuse_form_environment'}: $secvalue\n\n~;
					$not_body .= qq~$mbname, $guardian_txt{'main'}~;
					$not_subject =~ s~\&trade\;~~g;
					$not_body =~ s~\&trade\;~~g;
					&guardian_notify($not_to,$not_subject,$not_body,$not_from);
				}
				if($use_htaccess && $script_htaccess && !$iamadmin && !$iamgmod){
					&update_htaccess("add",$user_ip);
				}
				&fatal_error($guardian_txt{'script_reason'});
			}
		}
	}
return;
}
## subroutines below ##

sub guardian_notify {
	my ($to,$subject,$body,$from) = @_;
	my $result=&sendmail($to,$subject,$body,$from);
}

sub get_remote_port{
	if ($ENV{'REMOTE_PORT'}) {
		return $ENV{'REMOTE_PORT'};
	} else {
		return "empty";
	}
}

sub get_request_method {
	if ($ENV{'REQUEST_METHOD'}) {
		return $ENV{'REQUEST_METHOD'};
	} else {
		return "empty";
	}
}

sub get_script_name {
	if ($ENV{'SCRIPT_NAME'}) {
		return $ENV{'SCRIPT_NAME'};
	} else {
		return "empty";
	}
}

sub get_http_host {
	if ($ENV{'HTTP_HOST'}) {
		return $ENV{'HTTP_HOST'};
	} else {
		return "empty";
	}
}

sub get_query_string {
	if ($ENV{'QUERY_STRING'}) {
		my $tempstring = &str_replace("%09", "%20", $ENV{'QUERY_STRING'});
		return &str_replace("%09", "%20", $ENV{'QUERY_STRING'});
	} else {
		return "empty";
	}
}

sub get_user_agent {
	if ($ENV{'HTTP_USER_AGENT'}) {
		return $ENV{'HTTP_USER_AGENT'};
	} else {
		return "empty";
	}
}

sub get_referer {
	if ($ENV{'HTTP_REFERER'}) {
		return $ENV{'HTTP_REFERER'};
	} else {
		return "empty";
	}
}

sub get_ip {
	$client_ip = &get_client_ip; 		## HTTP_CLIENT_IP
	$x_forwarded = &get_x_forwarded; 	## HTTP_X_FORWARDED_FOR
	$x_ip_client = &get_x_ip_client; 	## X_IP_CLIENT
	$http_via = &get_http_via; 		## HTTP_VIA
	$remote_addr = &get_remote_addr; 	## REMOTE_ADDR
	if ($client_ip && $client_ip !~ m/empty/ && $client_ip !~ m/unknown/) {
		return $client_ip;
	} elsif ($x_forwarded && $x_forwarded !~ m/empty/ && $x_forwarded !~ m/unknown/) {
		return $x_forwarded;
	} elsif ($x_ip_client && $x_ip_client !~ m/empty/ && $x_ip_client !~ m/unknown/) {
		return $x_ip_client;
	} elsif ($http_via && $http_via !~ m/empty/ && $http_via !~ m/unknown/) {
		return $http_via;
	} elsif ($remote_addr && $remote_addr !~ m/empty/ && $remote_addr !~ m/unknown/) {
		return $remote_addr;
	} else {
		return "empty";
	}
}

sub get_client_ip {
	if($ENV{'HTTP_CLIENT_IP'} && $ENV{'HTTP_CLIENT_IP'} ne "127.0.0.1") {
		return $ENV{'HTTP_CLIENT_IP'};
	} else {
		return "empty";
	}
}

sub get_x_ip_client {
	if($ENV{'X_CLIENT_IP'} && $ENV{'X_CLIENT_IP'} ne "127.0.0.1") {
		return $ENV{'X_CLIENT_IP'};
	} else {
		return "empty";
	}
}

sub get_http_via {
	if($ENV{'HTTP_VIA'} && $ENV{'HTTP_VIA'} ne "127.0.0.1") {
		return $ENV{'HTTP_VIA'};
	} else {
		return "empty";
	}
}

sub get_x_forwarded {
	if($ENV{'HTTP_X_FORWARDED_FOR'}&& $ENV{'HTTP_X_FORWARDED_FOR'} ne "127.0.0.1") {
		return $ENV{'HTTP_X_FORWARDED_FOR'};
	} else {
		return "empty";
	}
}

sub get_remote_addr {
	if($ENV{'REMOTE_ADDR'}) {
		return $ENV{'REMOTE_ADDR'};
	} else {
		return "empty";
	}
}

sub str_replace {
	my($org,$repl,$target) = @_;
	$target =~ s~$org~$repl~ig;
	return $target;
}


sub update_htaccess {
	my($action,@values) = @_;
	my($htheader,$htfooter,@denies);
	if(!$action){return 0;}
	fopen(HTA,".htaccess");
	@htlines = <HTA>;
	fclose(HTA);
	## header to determine only who has access to the main script, not the admin script ##
	$htheader = qq~<Files YaBB*>\n~;
	$htfooter .= qq~</Files>\n~;
	foreach (@htlines){
		chomp $_;
		if($_ =~ m/Deny from /){
			$_ =~ s~Deny from ~~g;
			push (@denies, $_);
		}
	}
	if($action eq "add" || $action eq "remove" && $use_htaccess){
		fopen(HTA,">.htaccess");
		print HTA $htheader;
		foreach(@denies){
			chomp $_;
			chomp $values[0];
			if($_ ne $values[0]){print HTA "Deny from $_\n";}
		}
		if($action eq "add"){print HTA "Deny from $values[0]\n";}
		print HTA $htfooter;
		fclose(HTA);
	}	
}

1;