Current File : //usr/local/bin/csf/ConfigServer/Messenger.pm
###############################################################################
# Copyright 2006-2018, Way to the Web Limited
# URL: http://www.configserver.com
# Email: sales@waytotheweb.com
###############################################################################
## no critic (RequireUseWarnings, ProhibitExplicitReturnUndef, ProhibitMixedBooleanOperators, RequireBriefOpen)
# start main
package ConfigServer::Messenger;

use strict;
use lib '/usr/local/csf/lib';
use Fcntl qw(:DEFAULT :flock);
use File::Copy;
use JSON::Tiny;
use IO::Socket::INET;
use Net::CIDR::Lite;
use Net::IP;
use IPC::Open3;
use ConfigServer::Config;
use ConfigServer::CheckIP qw(checkip);
use ConfigServer::Logger qw(logfile);
use ConfigServer::URLGet;
use ConfigServer::Slurp qw(slurp);
use ConfigServer::GetIPs qw(getips);
use ConfigServer::GetEthDev;

use Exporter qw(import);
our $VERSION     = 2.00;
our @ISA         = qw(Exporter);
our @EXPORT_OK   = qw();

my $config = ConfigServer::Config->loadconfig();
my %config = $config->config();
my $ipv4reg = ConfigServer::Config->ipv4reg;
my $ipv6reg = ConfigServer::Config->ipv6reg;
if ($config{MESSENGER6}) {
	eval('use IO::Socket::INET6;'); ##no critic
	if ($@) {$config{MESSENGER6} = "0"}
}

my $childproc;
my $hostname;
if (-e "/proc/sys/kernel/hostname") {
	open (my $IN, "<", "/proc/sys/kernel/hostname");
	flock ($IN, LOCK_SH);
	$hostname = <$IN>;
	chomp $hostname;
	close ($IN);
} else {
	$hostname = "unknown";
}
my $hostshort = (split(/\./,$hostname))[0];

my %ips;
my $ipscidr6 = Net::CIDR::Lite->new;
&getethdev;
foreach my $ip (split(/,/,$config{RECAPTCHA_NAT})) {
	$ip =~ s/\s*//g;
	$ips{$ip} = 1;
}

# end main
###############################################################################
# start messenger
sub messenger {
	my $port = shift;
	my $user = shift;
	my $type = shift;
	my $oldtype = $type;
	my $server;
	my %sslcerts;
	my %sslkeys;

	$SIG{CHLD} = 'IGNORE';
	$SIG{INT} = \&childcleanup;
	$SIG{TERM} = \&childcleanup;
	$SIG{HUP} = \&childcleanup;
	$SIG{__DIE__} = sub {&childcleanup(@_);};
	$0 = "lfd $type messenger";
	$childproc = "Messenger ($type)";

	if ($type eq "HTTPS") {
		eval {
			local $SIG{__DIE__} = undef;
			require IO::Socket::SSL;
			import IO::Socket::SSL;
		};

		my $start = 0;
		my $format = "apache";
		my $sslhost;
		my $sslcert;
		my $sslkey;
		my $sslaliases;
		my %messengerports;
		foreach my $serverports (split(/\,/,$config{MESSENGER_HTTPS_IN})) {$messengerports{$serverports} = 1}
		foreach my $file (glob($config{MESSENGER_HTTPS_CONF})) {
			if (-e $file) {
				foreach my $line (slurp($file)) {
					$line =~ s/\'|\"//g;
					if ($line =~ /^\s*<VirtualHost\s+[^\>]+>/) {
						$start = 1;
						$format = "apache";
					}
					if ($format eq "apache" and $start) {
						if ($line =~ /\s*ServerName\s+(\w+:\/\/)?([a-zA-Z0-9\.\-]+)(:\d+)?/) {$sslhost = $2}
						if ($line =~ /\s*ServerAlias\s+(.*)/) {$sslaliases .= " ".$1}
						if ($line =~ /\s*SSLCertificateFile\s+(\S+)/) {
							my $match = $1;
							if (-e $match) {$sslcert = $match}
						}
						if ($line =~ /\s*SSLCertificateKeyFile\s+(\S+)/) {
							my $match = $1;
							if (-e $match) {$sslkey = $match}
						}
					}

#					if ($line =~ /^\s*listen\s+(\S+)\s*\;/) {
#						$start = 1;
#						unless ($messengerports{$1}) {$start = 0}
#						$format = "nginx";
#					}
#					if ($format eq "nginx" and $start) {
#						if ($line =~ /\s*server_name\s+(\S+)(((\s+\S+)*)?)\s*\;/) {
#							$sslhost = $1;
#							$sslaliases = $2;
#							$sslhost =~ s/:\d+//g;
#						}
#						if ($line =~ /\s*ssl_certificate\s+(\S+)\s*\;/) {
#							my $match = $1;
#							if (-e $match) {$sslcert = $1}
#						}
#						if ($line =~ /\s*ssl_certificate_key\s+(\S+)\s*\;/) {
#							my $match = $1;
#							if (-e $match) {$sslkey = $1}
#						}
#					}
					
					if (($format eq "apache" and $line =~ /^\s*<\/VirtualHost\s*>/) or 
						($format eq "nginx" and $line =~ /^\s*\}/)) {

						$start = 0;
						if ($sslhost ne "" and !checkip($sslhost) and $sslcert ne "") {
							$sslcerts{$sslhost} = $sslcert;
							if ($sslkey eq "") {$sslkey = $sslcert}
							$sslkeys{$sslhost} = $sslkey;
							foreach my $alias (split(/\s+/,$sslaliases)) {
								if ($alias eq "") {next}
								if (checkip($alias)) {next}
								if ($alias =~ /^[a-zA-Z0-9\.\-]+$/) {
									if ($config{MESSENGER_HTTPS_SKIPMAIL} and $alias =~ /^mail\./) {next}
									$sslcerts{$alias} = $sslcert;
									$sslkeys{$alias} = $sslkey;
								}
							}
						}
						$sslhost = "";
						$sslcert = "";
						$sslkey = "";
						$sslaliases = "";
					}
				}
			}
		}
		if (scalar(keys %sslcerts < 1)) {
			return (1, "No SSL certs found in MESSENGER_HTTPS_CONF location");
		}
		if (-e $config{MESSENGER_HTTPS_KEY}) {
			$sslkeys{''} = $config{MESSENGER_HTTPS_KEY};
		}
		if (-e $config{MESSENGER_HTTPS_CRT}) {
			$sslcerts{''} = $config{MESSENGER_HTTPS_CRT};
		}
		if ($config{DEBUG} >= 1) {
			foreach my $key (keys %sslcerts) {
				logfile("SSL: [$key] [$sslcerts{$key}] [$sslkeys{$key}]");
			}
		}
		eval {
			local $SIG{__DIE__} = undef;
			if ($config{MESSENGER6}) {
				$server = IO::Socket::SSL->new(
							Domain => AF_INET6,
							LocalPort => $port,
							Type => SOCK_STREAM,
							ReuseAddr => 1,
							Listen => $config{MESSENGER_CHILDREN},
							SSL_server => 1,
							SSL_use_cert => 1,
							SSL_cert_file => \%sslcerts,
							SSL_key_file => \%sslkeys,
				) or die("MESSENGER: *Error* cannot open server on port $port: ".IO::Socket::SSL->errstr);
			} else {
				$server = IO::Socket::SSL->new(
							Domain => AF_INET,
							LocalPort => $port,
							Type => SOCK_STREAM,
							ReuseAddr => 1,
							Listen => $config{MESSENGER_CHILDREN},
							SSL_server => 1,
							SSL_use_cert => 1,
							SSL_cert_file => \%sslcerts,
							SSL_key_file => \%sslkeys,
				) or die("MESSENGER: *Error* cannot open server on port $port: ".IO::Socket::SSL->errstr);
			}
			&logfile("Messenger HTTPS Service started for ".scalar(keys %sslcerts)." domains");
			$type = "HTML";
		};
		if ($@) {
			return (1, $@);
		}
	}
	elsif ($config{MESSENGER6}) {
		$server = IO::Socket::INET6->new(
			LocalPort => $port, 
			Type => SOCK_STREAM, 
			ReuseAddr => 1, 
			Listen => $config{MESSENGER_CHILDREN}) or &childcleanup(__LINE__,"*Error* cannot open server on port $port: $!");
	} else {
		$server = IO::Socket::INET->new(
			LocalPort => $port, 
			Type => SOCK_STREAM, 
			ReuseAddr => 1, 
			Listen => $config{MESSENGER_CHILDREN}) or &childcleanup(__LINE__,"*Error* cannot open server on port $port: $!");
	}
	
	my $index;
	if ($type eq "HTML" and $config{RECAPTCHA_SITEKEY} ne "") {$index = "/etc/csf/messenger/index.recaptcha.html"}
	elsif ($type eq "HTML") {$index = "/etc/csf/messenger/index.html"}
	else {$index = "/etc/csf/messenger/index.text"}
	open (my $IN, "<", $index);
	flock ($IN, LOCK_SH);
	my @message = <$IN>;
	close ($IN);
	chomp @message;

	my %images;
	if ($type eq "HTML") {
		opendir (DIR, "/etc/csf/messenger");
		foreach my $file (readdir(DIR)) {
			if ($file =~ /\.(gif|png|jpg)$/) {
				open (my $IN, "<", "/etc/csf/messenger/$file");
				flock ($IN, LOCK_SH);
				my @data = <$IN>;
				close ($IN);
				chomp @data;
				foreach my $line (@data) {
					$images{$file} .= "$line\n";
				}
			}
		}
		closedir (DIR);
	}

	if ($oldtype eq "HTTPS") {
		open (my $STATUS,"<", "/proc/$$/status") or next;
		flock ($STATUS, LOCK_SH);
		my @status = <$STATUS>;
		close ($STATUS);
		chomp @status;
		my $vmsize = 0;
		my $vmrss = 0;
		foreach my $line (@status) {
			if ($line =~ /^VmSize:\s+(\d+) kB$/) {$vmsize = $1}
			if ($line =~ /^VmRSS:\s+(\d+) kB$/) {$vmrss = $1}
		}

		logfile("lfd $oldtype messenger using $vmrss kB of RSS memory at startup, adding up to $config{MESSENGER_CHILDREN} children = ".(($config{MESSENGER_CHILDREN} + 1) * $vmrss)." kB");
		logfile("lfd $oldtype messenger using $vmsize kB of VIRT memory at startup, adding up to $config{MESSENGER_CHILDREN} children = ".(($config{MESSENGER_CHILDREN} + 1) * $vmsize)." kB");
	}

	if ($user ne "") {
		my (undef,undef,$uid,$gid,undef,undef,undef,$homedir) = getpwnam($user);
		if (($uid > 0) and ($gid > 0)) {
			local $( = $gid;
			local $) = "$gid $gid";
			local $> = local $< = $uid;
			if (($) != $gid) or ($> != $uid) or ($( != $gid) or ($< != $uid)) {
				logfile("MESSENGER_USER unable to drop privileges - stopping $oldtype Messenger");
				exit;
			}
			my %children;
			while (my ($client, $c_addr) = $server->accept()) {
				while (scalar (keys %children) >= $config{MESSENGER_CHILDREN}) {
					sleep 1;
					foreach my $pid (keys %children) {
						unless (kill(0,$pid)) {delete $children{$pid}}
					}
				}

				$SIG{CHLD} = 'IGNORE';
				my $pid = fork;
				$children{$pid} = 1;
				if ($pid == 0) {
					eval {
						local $SIG{__DIE__} = undef;
						local $SIG{'ALRM'} = sub {die};
						alarm(5);
						close $server;

						local $( = $gid;
						local $) = "$gid $gid";
						local $> = local $< = $uid;
						if (($) != $gid) or ($> != $uid) or ($( != $gid) or ($< != $uid)) {
							logfile("MESSENGER_USER unable to drop privileges - stopping $oldtype Messenger");
							exit;
						}

						$0 = "lfd $oldtype messenger client";

						binmode $client;
						$| = 1;
						my $firstline;

						my $hostaddress = $client->sockhost();
						my $peeraddress = $client->peerhost();
						unless ($peeraddress) {
							my($cport,$iaddr) = sockaddr_in($c_addr);
							$peeraddress = inet_ntoa($iaddr);
						}
						$peeraddress =~ s/^::ffff://;
						$hostaddress =~ s/^::ffff://;

						alarm(5);
						if ($type eq "HTML") {
							while ($firstline !~ /\n$/) {
								my $char;
								$client->read($char,1);
								$firstline .= $char;
								if ($char eq "") {exit}
								if (length $firstline > 2048) {last}
							}
							chomp $firstline;
						}

						alarm(5);
						my $error;
						my $success;
						my $failure;
						if (($type eq "HTML") and ($firstline =~ /^GET \/unblk\?g-recaptcha-response=(\S+)/i)) {
							my $recv = $1;
							my $status = 1;
							my $text;
							eval {
								local $SIG{__DIE__} = undef;
								eval("no lib '/usr/local/csf/lib'");
								my $urlget = ConfigServer::URLGet->new(2, "", $config{URLPROXY});
								my $url = "https://www.google.com/recaptcha/api/siteverify?secret=$config{RECAPTCHA_SECRET}&response=$recv";
								($status, $text) = $urlget->urlget($url);
							};
							if ($status) {
								logfile("*Error*, ReCaptcha ($peeraddress): $text");
								if ($config{DEBUG} >= 1) {
									if ($@) {$error .= "Error:".$@}
									if ($!) {$error .= "Error:".$!}
									$error .= " Error Status: $status";
								}
								$error .= "Unable to verify with Google reCAPTCHA";
							} else {
								my $resp  = JSON::Tiny::decode_json($text);
								if ($resp->{success}) {
									my $ip = $resp->{hostname};
									unless ($ip =~ /^($ipv4reg|$ipv6reg)$/) {$ip = (getips($ip))[0]}
									if ($ips{$ip} or $ip eq $hostaddress or $ipscidr6->find($ip)) {
										sysopen (my $UNBLOCK, "$homedir/unblock.txt", O_WRONLY | O_APPEND | O_CREAT) or $error .= "Unable to write to [$homedir/unblock.txt] (make sure that MESSENGER_USER has a home directory)";
										flock($UNBLOCK, LOCK_EX);
										print $UNBLOCK "$peeraddress;$resp->{hostname};$ip\n";
										close ($UNBLOCK);
										$success = 1;
										logfile("*Success*, ReCaptcha ($peeraddress): [$resp->{hostname} ($ip)] requested unblock");
									} else {
										$error .= "Failed, [$resp->{hostname} ($ip)] does not appear to be hosted on this server.";
										logfile("*Failed*, ReCaptcha ($peeraddress): [$resp->{hostname} ($ip)] does not appear to be hosted on this server");
									}
								} else {
									$failure = 1;
								}
							}
						}
						if (($type eq "HTML") and ($firstline =~ /^GET\s+(\S*\/)?(\S*\.(gif|png|jpg))\s+/i)) {
							my $type = $3;
							if ($type eq "jpg") {$type = "jpeg"}
							print $client "HTTP/1.1 200 OK\r\n";
							print $client "Content-type: image/$type\r\n";
							print $client "\r\n";
							print $client $images{$2};
						} else {
							if ($type eq "HTML") {
								print $client "HTTP/1.1 403 OK\r\n";
								print $client "Content-type: text/html\r\n";
								print $client "\r\n";
							}
							foreach my $line (@message) {
								if ($line =~ /\[IPADDRESS\]/) {$line =~ s/\[IPADDRESS\]/$peeraddress/}
								if ($line =~ /\[HOSTNAME\]/) {$line =~ s/\[HOSTNAME\]/$hostname/}
								if ($line =~ /\[RECAPTCHA_SITEKEY\]/) {$line =~ s/\[RECAPTCHA_SITEKEY\]/$config{RECAPTCHA_SITEKEY}/}
								if ($line =~ /\[RECAPTCHA_ERROR=\"([^\"]+)\"\]/) {
									my $text = $1;
									if ($error ne "") {$line =~ s/\[RECAPTCHA_ERROR=\"([^\"]+)\"\]/$text $error/} else {$line =~ s/\[RECAPTCHA_ERROR=\"([^\"]+)\"\]//}
								}
								if ($line =~ /\[RECAPTCHA_SUCCESS=\"([^\"]+)\"\]/) {
									my $text = $1;
									if ($success) {$line =~ s/\[RECAPTCHA_SUCCESS=\"([^\"]+)\"\]/$text/} else {$line =~ s/\[RECAPTCHA_SUCCESS=\"([^\"]+)\"\]//}
								}
								if ($line =~ /\[RECAPTCHA_FAILURE=\"([^\"]+)\"\]/) {
									my $text = $1;
									if ($failure) {$line =~ s/\[RECAPTCHA_FAILURE=\"([^\"]+)\"\]/$text/} else {$line =~ s/\[RECAPTCHA_FAILURE=\"([^\"]+)\"\]//}
								}
								print $client "$line\r\n";
							}
						}
						shutdown ($client,2);
						close ($client);
						alarm(0);
						exit;
					};
					alarm(0);
					exit;
				}
			}
		} else {
			logfile("MESSENGER_USER invalid - stopping $oldtype Messenger");
		}
	} else {
		logfile("MESSENGER_USER not set - stopping $oldtype Messenger");
	}
	return;
}
# end messenger
###############################################################################
# start messengerv2
sub messengerv2 {
	my (undef,undef,$uid,$gid,undef,undef,undef,$homedir) = getpwnam($config{MESSENGER_USER});
	if ($homedir eq "" or $homedir eq "/" or $homedir =~ m[/etc/csf]) {
		return (1, "The home directory for $config{MESSENGER_USER} is not valid [$homedir]");
	}
	if (! -e $homedir) {
		return (1, "The home directory for $config{MESSENGER_USER} does not exist [$homedir]");
	}
	system("chmod","711",$homedir);
	my $public_html = $homedir."/public_html";
	unless (-e $public_html) {
		system("mkdir","-p",$public_html);
		system("chown","$config{MESSENGER_USER}:nobody",$public_html);
		system("chmod","711",$public_html);
	}
	unless (-e $public_html."/.htaccess") {
		open (my $HTACCESS, ">", $public_html."/.htaccess");
		flock ($HTACCESS, LOCK_EX);
		print $HTACCESS "DirectoryIndex index.php index.cgi index.html index.htm\n";
		print $HTACCESS "Options +FollowSymLinks +ExecCGI\n";
		print $HTACCESS "RewriteEngine On\n";
		print $HTACCESS "RewriteCond \%{REQUEST_FILENAME} !-f\n";
		print $HTACCESS "RewriteCond \%{REQUEST_FILENAME} !-d\n";
		print $HTACCESS "RewriteRule ^ /index.php [L,QSA]\n";
		system("chown","$config{MESSENGER_USER}:$config{MESSENGER_USER}",$public_html."/.htaccess");
		system("chmod","644",$public_html."/.htaccess");
	}
	unless (-e $public_html."/index.php") {
		if ($config{RECAPTCHA_SITEKEY}) {
			system("cp","/etc/csf/messenger/index.recaptcha.php",$public_html."/index.php");
		} else {
			system("cp","/etc/csf/messenger/index.php",$public_html."/index.php");
		}
		system("chown","$config{MESSENGER_USER}:$config{MESSENGER_USER}",$public_html."/index.php");
		system("chmod","644",$public_html."/index.php");
	}
	unless (-e $homedir."/en.php") {
		system("cp","/etc/csf/messenger/en.php",$homedir."/en.php");
		system("chown","$config{MESSENGER_USER}:$config{MESSENGER_USER}",$homedir."/en.php");
		system("chmod","644",$homedir."/en.php");
	}
	open (my $CONF, ">", $homedir."/recaptcha.php");
	flock ($CONF, LOCK_EX);
	print $CONF "<?php\n";
	print $CONF "\$secret = '$config{RECAPTCHA_SECRET}';\n";
	print $CONF "\$sitekey = '$config{RECAPTCHA_SITEKEY}';\n";
	print $CONF "\$unblockfile = '$homedir/unblock.txt';\n";
	print $CONF "\$logfile = '/var/log/lfd_messenger.log';\n";
	print $CONF "?>\n";
	system("chown","$config{MESSENGER_USER}:$config{MESSENGER_USER}",$homedir."/recaptcha.php");
	system("chmod","644",$homedir."/recaptcha.php");

	
	open (my $OUT, ">", "/var/lib/csf/csf.conf");
	flock ($OUT, LOCK_EX);

	if ($config{MESSENGER_HTML_IN} ne "") {
# use std template
		print $OUT "Listen 0.0.0.0:$config{MESSENGER_HTML}\n";
		if ($config{IPV6}) {print $OUT "Listen [::]:$config{MESSENGER_HTML}\n"}
		print $OUT "<VirtualHost *:$config{MESSENGER_HTML}>\n";
		print $OUT " ServerName $hostname\n";
		print $OUT " DocumentRoot $public_html\n";
		print $OUT " <Directory \"$homedir\">\n";
		print $OUT "  AllowOverride All\n";
		print $OUT " </Directory>\n";
		print $OUT " <IfModule suphp_module>\n";
		print $OUT "   suPHP_UserGroup $config{MESSENGER_USER} $config{MESSENGER_USER}\n";
		print $OUT " </IfModule>\n";
		print $OUT " <IfModule suexec_module>\n";
		print $OUT "   <IfModule !mod_ruid2.c>\n";
		print $OUT "     SuexecUserGroup $config{MESSENGER_USER} $config{MESSENGER_USER}\n";
		print $OUT "   </IfModule>\n";
		print $OUT " </IfModule>\n";
		print $OUT " <IfModule ruid2_module>\n";
		print $OUT "   RMode config\n";
		print $OUT "   RUidGid $config{MESSENGER_USER} $config{MESSENGER_USER}\n";
		print $OUT " </IfModule>\n";
		print $OUT " <IfModule mpm_itk.c>\n";
		print $OUT "   AssignUserID $config{MESSENGER_USER} $config{MESSENGER_USER}\n";
		print $OUT " </IfModule>\n";
		print $OUT "</VirtualHost>\n";
	}

	if ($config{MESSENGER_HTTPS_IN} ne "") {
		my %sslcerts;
		my %sslkeys;
		my %ssldomains;
		my $start = 0;
		my $format = "apache";
		my $sslhost;
		my $sslcert;
		my $sslkey;
		my $sslaliases;
		my $ssldir = "/var/lib/csf/ssl/";
		unless (-d $ssldir) {
			mkdir $ssldir;
			mkdir $ssldir."certs/";
			mkdir $ssldir."keys/";
		}
		foreach my $file (glob($config{MESSENGER_HTTPS_CONF})) {
			if (-e $file) {
				foreach my $line (slurp($file)) {
					$line =~ s/\'|\"//g;
					if ($line =~ /^\s*<VirtualHost\s+[^\>]+>/) {
						$start = 1;
						$format = "apache";
					}
					if ($format eq "apache" and $start) {
						if ($line =~ /\s*ServerName\s+(\w+:\/\/)?([a-zA-Z0-9\.\-]+)(:\d+)?/) {$sslhost = $2}
						if ($line =~ /\s*ServerAlias\s+(.*)/) {$sslaliases .= " ".$1}
						if ($line =~ /\s*SSLCertificateFile\s+(\S+)/) {
							my $match = $1;
							if (-e $match) {
								copy($match, $ssldir."certs/".$sslhost."\.crt");
								$sslcert = $ssldir."certs/".$sslhost."\.crt";
							}
						}
						if ($line =~ /\s*SSLCertificateKeyFile\s+(\S+)/) {
							my $match = $1;
							if (-e $match) {
								copy($match, $ssldir."keys/".$sslhost."\.key");
								$sslkey = $ssldir."keys/".$sslhost."\.key";
							}
						}
					}
					
					if (($format eq "apache" and $line =~ /^\s*<\/VirtualHost\s*>/)) {
						$start = 0;
						if ($sslhost ne "" and !checkip($sslhost) and $sslcert ne "") {
							$ssldomains{$sslhost}{key} = $sslkey;
							$ssldomains{$sslhost}{aliases} = $sslaliases;
							$ssldomains{$sslhost}{cert} = $sslcert;
						}
						$sslhost = "";
						$sslcert = "";
						$sslkey = "";
						$sslaliases = "";
					}
				}
			}
		}
		if (scalar(keys %ssldomains < 1)) {
			return (1, "No SSL domains found in MESSENGER_HTTPS_CONF location");
		}

		print $OUT "Listen 0.0.0.0:$config{MESSENGER_HTTPS}\n";
		if ($config{IPV6}) {print $OUT "Listen [::]:$config{MESSENGER_HTTPS}\n"}
		if (-e $config{MESSENGER_HTTPS_KEY}) {
			print $OUT "<VirtualHost *:$config{MESSENGER_HTTPS}>\n";
			print $OUT " ServerName $hostname\n";
			print $OUT " DocumentRoot $public_html\n";
			print $OUT " UseCanonicalName Off\n";
			print $OUT " <Directory \"$homedir\">\n";
			print $OUT "  AllowOverride All\n";
			print $OUT " </Directory>\n";
			print $OUT " <IfModule suphp_module>\n";
			print $OUT "   suPHP_UserGroup $config{MESSENGER_USER} $config{MESSENGER_USER}\n";
			print $OUT " </IfModule>\n";
			print $OUT " <IfModule suexec_module>\n";
			print $OUT "   <IfModule !mod_ruid2.c>\n";
			print $OUT "     SuexecUserGroup $config{MESSENGER_USER} $config{MESSENGER_USER}\n";
			print $OUT "   </IfModule>\n";
			print $OUT " </IfModule>\n";
			print $OUT " <IfModule ruid2_module>\n";
			print $OUT "   RMode config\n";
			print $OUT "   RUidGid $config{MESSENGER_USER} $config{MESSENGER_USER}\n";
			print $OUT " </IfModule>\n";
			print $OUT " <IfModule mpm_itk.c>\n";
			print $OUT "   AssignUserID $config{MESSENGER_USER} $config{MESSENGER_USER}\n";
			print $OUT " </IfModule>\n";
			print $OUT " SSLEngine on\n";
			if (-e $config{MESSENGER_HTTPS_KEY}) {
				copy($config{MESSENGER_HTTPS_KEY}, $ssldir."keys/".$hostname."\.key");
				print $OUT " SSLCertificateKeyFile ".$ssldir."keys/".$hostname."\.key\n";
			}
			if (-e $config{MESSENGER_HTTPS_CRT}) {
				copy($config{MESSENGER_HTTPS_CRT}, $ssldir."certs/".$hostname."\.crt");
				print $OUT " SSLCertificateFile ".$ssldir."certs/".$hostname."\.crt\n";
			}
			print $OUT " SSLUseStapling off\n";
			print $OUT "</VirtualHost>\n";
		}
		foreach my $key (keys %ssldomains) {
			if ($key eq "") {next}
			if ($key =~ /^\s+$/) {next}
			if (-e $ssldomains{$key}{cert}) {
				print $OUT "<VirtualHost *:$config{MESSENGER_HTTPS}>\n";
				print $OUT " ServerName $key\n";
				print $OUT " ServerAlias $ssldomains{$key}{aliases}\n";
				print $OUT " DocumentRoot $public_html\n";
				print $OUT " UseCanonicalName Off\n";
				print $OUT " <Directory \"$homedir\">\n";
				print $OUT "  AllowOverride All\n";
				print $OUT " </Directory>\n";
				print $OUT " <IfModule suphp_module>\n";
				print $OUT "   suPHP_UserGroup $config{MESSENGER_USER} $config{MESSENGER_USER}\n";
				print $OUT " </IfModule>\n";
				print $OUT " <IfModule suexec_module>\n";
				print $OUT "   <IfModule !mod_ruid2.c>\n";
				print $OUT "     SuexecUserGroup $config{MESSENGER_USER} $config{MESSENGER_USER}\n";
				print $OUT "   </IfModule>\n";
				print $OUT " </IfModule>\n";
				print $OUT " <IfModule ruid2_module>\n";
				print $OUT "   RMode config\n";
				print $OUT "   RUidGid $config{MESSENGER_USER} $config{MESSENGER_USER}\n";
				print $OUT " </IfModule>\n";
				print $OUT " <IfModule mpm_itk.c>\n";
				print $OUT "   AssignUserID $config{MESSENGER_USER} $config{MESSENGER_USER}\n";
				print $OUT " </IfModule>\n";
				print $OUT " SSLEngine on\n";
				if (-e $ssldomains{$key}{cert}) {print $OUT " SSLCertificateFile $ssldomains{$key}{cert}\n"}
				if (-e $ssldomains{$key}{key}) {print $OUT " SSLCertificateKeyFile $ssldomains{$key}{key}\n"}
				print $OUT " SSLUseStapling off\n";
				print $OUT "</VirtualHost>\n";
			}
		}
	}
	close ($OUT);

	system("cp","-f","/var/lib/csf/csf.conf","/etc/apache2/conf.d/csf.messenger.conf");

	my ($childin, $childout);
	my $cmdpid = open3($childin, $childout, $childout, "/usr/sbin/apachectl", "configtest");
	my @data = <$childout>;
	waitpid ($cmdpid, 0);

	if (-e "/var/lib/csf/apachectl.error") {unlink("/var/lib/csf/apachectl.error")}
	my $ok = 0;
	foreach (@data) {
		if ($_ =~ /^Syntax OK/) {$ok = 1}
	}
	if ($ok) {
		system("/scripts/restartsrv_httpd");
		logfile("MESSENGERV2: Started Apache MESSENGERV2 service using /etc/apache2/conf.d/csf.messenger.conf");
	} else {
		logfile("*MESSENGERV2*: Unable to generate a valid Apache configuration, see /var/lib/csf/apachectl.error");
		if (-e "/etc/apache2/conf.d/csf.messenger.conf") {unlink("/etc/apache2/conf.d/csf.messenger.conf")}
		system("/scripts/restartsrv_httpd");
		
		open (my $ERROR, ">", "/var/lib/csf/apachectl.error");
		flock ($ERROR, LOCK_EX);
		foreach (@data) {print $ERROR $_}
		close ($ERROR);
	}
	return;
}
# end messengerv2
###############################################################################
# start childcleanup
sub childcleanup {
	$SIG{INT} = 'IGNORE';
	$SIG{TERM} = 'IGNORE';
	$SIG{HUP} = 'IGNORE';
	my $line = shift;
	my $message = shift;

	if (($message eq "") and $line) {
		$message = "Child $childproc: $line";
		$line = "";
	}

	$0 = "child - aborting";

	if ($message) {
		if ($line ne "") {$message .= ", at line $line"}
		logfile("$message");
	}
    exit;
}
# end childcleanup
###############################################################################
# start getethdev
sub getethdev {
	my $ethdev = ConfigServer::GetEthDev->new();
	my %g_ipv4 = $ethdev->ipv4;
	my %g_ipv6 = $ethdev->ipv6;
	foreach my $key (keys %g_ipv4) {
		my $netip = Net::IP->new($key);
		my $type = $netip->iptype();
		if ($type eq "PUBLIC") {$ips{$key} = 1}
	}
	if ($config{IPV6}) {
		foreach my $key (keys %g_ipv6) {
			if ($key !~ m[::1/128]) {
				eval {
					local $SIG{__DIE__} = undef;
					$ipscidr6->add($key);
				};
			}
		}
	}
	return;
}
# end getethdev
###############################################################################

1;