File: //dev/shm/rctmp
ggsession="$$"
#!/bin/bash
#Global Variables
version="1.5a \"GGVPS Troubleautomagic - Support Dev Edition\""
G="\e[30;48;5;82m"
CYAN="$(tput setaf 6)"
M="$(tput setaf 5)"
B="\e[48;5;196m"
CLEAR="\033[0m"
NC=$(tput sgr0)
if [[ -f mrun ]]; then
alias ggexit="kill -1 $$"
rm -rf mrun
else
alias ggexit="kill -1 $ggsession"
fi
PATH=$PATH:/scripts/
#Setting Hostname Variables
if [[ -f /usr/bin/hostname ]];then
HOSTNAMEBIN=/usr/bin/hostname
elif [[ -f /bin/hostname ]];then
HOSTNAMEBIN=/bin/hostname
else
HOSTNAMEBIN=hostname
fi
#Set Variables for node/container
vzCTID=`awk '{print $1}' /proc/vz/veinfo`
#vzNODE=`traceroute -T -N1 -m1 -q1 -w0 8.8.8.8|grep -v traceroute|head -n1|tail -n1|awk '{print $2}'| awk -F'.' '{print $1}'`
OS=$(rpm -E %{rhel})
#PS1 Fix for Dual Bash
PS1="[\u@\h \W]\$ "
#Display/CTA Functions
function good() {
GREEN='\033[0;32m'
echo -e "${GREEN}\xE2\x9C\x94 $1${NC} "
}
function good2() {
echo "$G $1 $CLEAR"
}
function bad() {
RED='\033[0;31m'
echo -e "${RED}X $1${NC}"
}
function bad2() {
echo "$B $1 $CLEAR"
}
function SOUT(){
printf "[$1]\n"
printf "$2\n"
}
#Script Functions
alias sushell='whmapi1 modifyacct user=$(stat -c %U .) HASSHELL=1 && su $(stat -c %U .)'
alias summary='wget -O summary.php https://dl.websitehostserver.net/vps-files/summary.txt;php summary.php'
alias ll='ls -lAh --color'
alias ls='ls --color'
alias fixlicense='/usr/local/cpanel/cpkeyclt'
alias exit='echo "You must use ggexit to close this session."'
alias logout='echo "You must use ggexit to close this session."'
alias install-softaculous='curl https://dl.websitehostserver.net/vps-files/softaculous_install.sh.txt | bash'
alias exim-security="cat /etc/exim.conf | grep -E 'openssl_options|tls_require_ciphers'"
function enable-root(){
sed -i s/"PasswordAuthentication no"/"PasswordAuthentication yes"/g /etc/ssh/sshd_config
sed -i s/"PermitRootLogin without-password"/"PermitRootLogin yes"/g /etc/ssh/sshd_config
service sshd restart
echo "Root access has been enabled."
}
function disable-root(){
sed -i s/"PasswordAuthentication yes"/"PasswordAuthentication no"/g /etc/ssh/sshd_config
sed -i s/"PermitRootLogin yes"/"PermitRootLogin without-password"/g /etc/ssh/sshd_config
service sshd restart
echo "Root access has been disabled."
}
#### TOPS Req. Functions #####
# Function to show the biggest files and directories
show_biggest() {
echo "Top $1 biggest $2 in $3:"
du -ah --threshold=100M --max-depth=1 "$3" | sort -rh | head -n $1 | awk '{printf "%-50s %s\n", $2, $1}'
echo ""
}
# Function to display usage information
display_usage() {
echo "Usage: tops [number_of_files] -d <directory>"
echo "Options:"
echo " -h Display usage information"
echo " -d Specify the directory to view the largest files/directories"
}
##############################
tops() {
# Script Name: top.sh
# Author: Keith M
# Description: A script to display the top largest files and directories in a specified directory.
# Usage: tops [number_of_files] -d <directory>
# Version: 0.2
# Options:
# -h Display usage information
# -d Specify the directory to view the largest files/directories
#exit hack by Catie
do_nothing=false
# Check if the -h flag is used for usage information
if [ "$1" == "-h" ]; then
display_usage
do_nothing=true
fi
if [ "$do_nothing" == false ]; then
# Check if the -d flag is used
if [ "${1:0:2}" == "-d" ]; then
if [ -z "$2" ]; then
display_usage
do_nothing=true
fi
directory="$2"
num_files=10
show_biggest "$num_files" "files and directories" "$directory"
do_nothing=true
fi
fi
if [ "$do_nothing" == false ]; then
# Check if the number of files is provided
if [ "$#" -ge 1 ] && [ "$1" -gt 0 ]; then
num_files="$1"
shift # Remove the first argument (number_of_files) from the arguments list
else
num_files=10
fi
# Check if the -d flag is used and a directory is provided
if [ "$#" -ge 2 ] && [ "$1" == "-d" ]; then
if [ -z "$2" ]; then
display_usage
do_nothing=true
fi
if [ "$do_nothing" == false ]; then
directory="$2"
show_biggest "$num_files" "files and directories" "$directory"
fi
else
# Show the top number of files in the /home/ and /backup/ directories
for user_dir in /home/*; do
if [ -d "$user_dir" ] && [ "$(basename "$user_dir")" != "virtfs" ] && [ "$(basename "$user_dir")" != "csf" ]; then
show_biggest "$num_files" "files and directories" "$user_dir"
fi
done
# Show the top number of files in the /backup/ directory
show_biggest "$num_files" "files and directories" "/backup/"
fi
fi
}
function ec(){
# Pass all arguments to the Perl script using command substitution
perl_result="$(perl - "$@" <<'EOF'
#################################################################
# ecpp_3.pl - Updated by RJ
# Utility to parse and generate statistics from mail logs.
#
#################################################################
my $version = "20230512";
use strict;
use warnings;
use Time::Local;
use Time::localtime;
use POSIX qw(strftime);
use File::stat;
use Getopt::Long;
use IO::Uncompress::Gunzip;
use FileHandle;
sub usage;
sub findmailcreation;
sub populatedomainmap;
sub populateownermap;
sub getsearchusers;
sub getfixedlogins;
sub mailcount;
sub eximlogstart;
sub processeximlogs;
sub recordsample;
sub addemail;
sub parseeximline;
sub commify;
sub printtotals;
sub formatsample;
sub printsamples;
sub printhourly;
sub printsendaddr;
sub printsendlog;
sub printcwd;
sub printsubs;
sub printrecaddr;
sub printexim;
sub printtimerange;
sub maillogstart;
sub processmaillogs;
sub parsemailline;
sub pseudoui;
sub get_homedir;
$| = 1; #turn on autoflush of stdout (allows progress code to work correctly)
# begin maincode
print "ecpp_2.pl - Version: $version \n\n";
my $starthours = 48;
my $endhours = 0;
my $days = 0;
my $resellermode = 0;
my $findemailcreate = 0;
my $imappopips = 1;
my $tos = 0;
my $terse = 1;
my $lowmem = 0; # skip recording of recipient/topic/sender info for memory/cpu constrained servers
# grab the timezone offset, so that we can make timegm work right (it's much faster than timelocal)
my @time = CORE::localtime(time);
my $offset = timegm(@time) - timelocal(@time);
# grab command line options
GetOptions ('shours|s|hours|h=i' => \$starthours,
'ehours|e=i' => \$endhours,
'days|d=i' => \$days,
'reseller|r' => \$resellermode,
'create|c' => \$findemailcreate,
'ips|i=i' => \$imappopips,
'terse|t=i' => \$terse,
'lowmem|l|fast|f' => \$lowmem);
if (!exists $ARGV[0]) { #quick check to make sure we have an argument
usage();
} elsif ($findemailcreate) {
findmailcreation($ARGV[0]);
} else {
mailcount($ARGV[0], $starthours, $endhours, $days, $resellermode, $imappopips, $tos);
}
exit 0;
# end maincode
sub usage {
print <<EOU;
No argument provided.
Default usage, assumes you wish to parse the last 48 hours of logs:
# ec <username>
# ec <domain>
Parse the last <hours> hours worth of logs:
# ec -h <hours> <user or domain>
# ec --hours=<hours> <user or doman>
Parse between the last <start hours> and <end hours> marks:
# ec -s <start hours> -e <end hours> <user or doman>
# ec --shours=<start hours> --ehours=<end hours> <user or doman>
Parse for the last <days> day period:
# ec -d <days>
# ec --days=<days>
Search across all users for a reseller:
# ec --reseller <reseller account>
# ec -r <reseller account>
Search for the log excerpt and creation time of an email address:
# ec -c <email address>
Some example use cases:
# ec teammast
# ec --hours=48 teammast
# ec -s 48 -e 24 teammast
# ec -h 48 -r mrowner
# ec -c alex\@rugbysuccess.com
EOU
}
sub findmailcreation {
my $emailaddress = $_[0];
my $cparchlogp = "/usr/local/cpanel/logs/archive";
my @cplogs= ("/usr/local/cpanel/logs/access_log");
my ($emailuser, $emaildomain) = ($emailaddress =~ /^([^@]*)[\+@](.*)$/);
if ($emailuser && $emaildomain) {
print "Finding the creation time of: $emailaddress\n";
print "User: $emailuser\n";
print "Domain: $emaildomain\n\n";
# add archived cpanel logs to list
opendir(my $archivedh, $cparchlogp);
while(my $file = readdir($archivedh)) {
if ($file =~ /access_log-.*?\.gz/) {
push (@cplogs, "$cparchlogp/$file");
}
}
closedir($archivedh);
@cplogs = sort { stat($b)->mtime <=> stat($a)->mtime } @cplogs;
# search through logs for creation
my $createrex = "addpop&email=$emailuser&password=__HIDDEN__"a=[^&]*&domain=$emaildomain&";
my $found = 0;
foreach my $file (@cplogs) {
print "Processing: $file\n";
my $progress = -1;
my $filesize = stat($file)->size;
my $fh = new FileHandle;
$fh->open("<$file");
my $fhp;
if ($file =~ /^.*?\.gz$/) {
$fhp = new IO::Uncompress::Gunzip $fh;
} else {
$fhp = $fh;
}
my $istty = (-t STDOUT);
while(my $line = <$fhp>) {
if($line =~ /$createrex/) {
print "\nCreation of email address found: \n\n$line";
$found = 1;
last;
}
if (int((tell($fh) / $filesize) * 100 ) > $progress){ #prevent a billion slow i/o calls
$progress = int((tell($fh) / $filesize) * 100 );
if ($istty) {
print "\r \rProgress: $progress%"; #replace prev line with new progress
} else {
if (($progress == 0) || ($progress % 10 == 0)) {
print "$progress%";
} else {
print ".";
}
}
}
}
$fh->close();
print "\n";
if ($found) {
last;
}
}
} else {
print "Invalid email address provided.\n";
}
}
# populate user2domain and domain2user maps
sub populatedomainmap {
my $userpath = "/etc/userdomains";
my %user2domain = (); # hash of arrays for user -> domains map
my %domain2user = (); # hash for domain -> user map
open (USERDOMAINS, $userpath) or die;
while (my $line = <USERDOMAINS>) {
chomp($line); # Kill trailing whitespace/newline
my @temp = split(": ", $line); # userdomains format is "domain.com: user"
$domain2user{ $temp[0] } = $temp[1];
push @{ $user2domain{ $temp[1]} }, $temp[0];
}
close (USERDOMAINS);
return (\%user2domain, \%domain2user);
}
sub populateownermap {
my %owner2user = (); # hash for owner -> user map
my $tuopath = "/etc/trueuserowners";
open (TUOWNER, $tuopath) or die;
while (my $line = <TUOWNER>) {
chomp($line); # Kill trailing whitespace/newline
if ($line =~ /^.*?:\s.*?$/) {
my @temp = split(": ", $line); # trueuserowners format is "user: owner"
push @{ $owner2user{ $temp[1]} }, $temp[0];
}
}
close (TUOWNER);
return %owner2user;
}
sub getsearchusers {
my ($baseowner, $reseller, $user2domain_r) = @_;
my @searchusers;
# if reseller mode was specified, add sub-accounts to checklist, otherwise just add the user
if ($baseowner eq "root") { # if we are root, add all the users to the list
print "Entire Server Mode.\n";
for my $user (keys %{$user2domain_r}) {
push (@searchusers, $user);
}
} elsif ($reseller) {
print "Reseller Mode.\n";
my %owner2user = populateownermap();
if (!(exists $owner2user{$baseowner})) {
print "$baseowner does not appear to be a reseller.\n";
} else {
foreach (@{$owner2user{$baseowner}}) {
push(@searchusers, $_);
}
}
} else {
print "Single User Mode.\n";
push (@searchusers, $baseowner);
}
return @searchusers;
}
sub getfixedlogins {
my ($sur, $u2sr) = @_;
my @searchusers = @{$sur};
my %user2domain = %{$u2sr};
my %fixedloginsh;
foreach my $user (@searchusers) {
$fixedloginsh{$user} = undef;
print "\nEmail accounts per domain owned by $user:\n";
foreach my $domain (@{$user2domain{$user}}) {
my $count = 0;
if(open(SHADOW, "< ".get_homedir($user)."/etc/$domain/shadow")) {
while (<SHADOW>) {
$count++;
}
close(SHADOW);
}
print "\t$domain: $count\n";
$fixedloginsh{$domain} = undef;
}
}
return \%fixedloginsh;
}
sub mailcount {
my ($arg, $starthours, $endhours, $days, $reseller, $imappopips, $tos) = @_;
# check to see if the argument were were provided us a user or domain
my $baseowner;
my ($user2domainr, $domain2userr) = populatedomainmap();
my %user2domain = %{$user2domainr};
my %domain2user = %{$domain2userr};
$arg = lc($arg);
if (exists ($user2domain{$arg}) || ($arg eq "root")) {
$baseowner = $arg;
print "$arg is a USER.\n";
} elsif (exists $domain2user{$arg}) {
$baseowner = $domain2user{$arg};
print "$arg is a DOMAIN.\n";
print "$arg is owned by USER $domain2user{$arg}\n";
} else {
print "$arg appears to be nothing useful, quitting.\n";
return;
}
if ($days) {
$starthours = ($days * 24);
$endhours = 0;
}
if ($endhours > $starthours) { #sanity check
print "Invalid time range, ends before it starts. Assuming you were confused, swapping.\n";
($starthours, $endhours) = ($endhours, $starthours);
}
my $currentTime = time;
my $endTime = $currentTime - ($endhours * 3600);
my $startTime = $currentTime - ($starthours * 3600);
my @searchusers = getsearchusers($baseowner, $reseller, \%user2domain);
my $fixedlogins_r = getfixedlogins(\@searchusers, \%user2domain);
print "\n";
my %ipaddr; # ip addresses logging in via POP/IMAP
if ($imappopips) {
my ($ipaddr_r) = processmaillogs(\@searchusers, $fixedlogins_r, $startTime, $endTime);
%ipaddr = %{$ipaddr_r};
}
my ($totec_r, $trec_r, $fsp_r, $lsp_r, $cnt_r, $raddr_r, $slog_r, $saddr_r, $mid_r, $bcnt_r, $bcnt_h_r,
$cwd_r, $sub_r, $usercnt_r, $userraddr_r, $bcnt_rec_r)
= processeximlogs(\@searchusers, $fixedlogins_r, \%ipaddr, $startTime, $endTime);
my $totec = ${$totec_r}; # total email count
my $trec = ${$trec_r}; # true email count (multiple recipients separated)
my @fsp = @{$fsp_r}; # first samples
my @lsp = @{$lsp_r}; # last samples
my %cnt = %{$cnt_r}; # per user count
my %raddr = %{$raddr_r}; # receiving addresses
my %slog = %{$slog_r}; # sender logins
my %saddr = %{$saddr_r}; # sender addresses
my %mid = %{$mid_r};
my %cwd = %{$cwd_r}; # current working directories
my %sub = %{$sub_r}; # subjects
my %usercnt = %{$usercnt_r}; # per user count
my %userraddr = %{$userraddr_r}; #per user count recipients
my %bcnt = %{$bcnt_r};
my %bcnt_h = %{$bcnt_h_r};
my %bcnt_rec = %{$bcnt_rec_r};
print "\n"; print '-' x25 . "\n\n";
pseudoui($baseowner); print "\n";
print '-' x25 . "\n\n";
printtimerange($startTime, $endTime);
printtotals($trec, \%raddr, \%bcnt, \%bcnt_rec);
printhourly(\%cnt, \%bcnt_h, \%usercnt, \%slog, \%userraddr);
unless($lowmem) {
printsendaddr(\%saddr);
printsendlog(\%slog);
}
printcwd(\%cwd);
unless($lowmem) {
printrecaddr(\%raddr);
printsubs(\%sub);
}
printsamples(\@fsp, \@lsp);
printexim(\%saddr);
}
sub eximlogstart {
my ($file) = @_;
my $fh = new FileHandle;
$fh->open("<$file");
my $fhp;
if ($file =~ /^.*?\.gz$/) {
$fhp = new IO::Uncompress::Gunzip $fh;
} else {
$fhp = $fh;
}
my $time;
while(my $line = <$fhp>) {
if ($line =~ /(\d{4})\-(\d{2})\-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s/) {
$time = timelocal($6, $5, $4, $3, $2 - 1, $1);
last;
}
}
$fh->close();
return $time;
}
sub processeximlogs {
my ($searchusers_r, $fixedlogins_r, $ipaddr, $startTime, $endTime) = @_;
my @searchusers = @{$searchusers_r};
# specify logs to search
my @eximlogs = @{findlogs('/var/log', 'exim_mainlog((-\d{8})|(\.\d))?(\.gz)?')};
# setup hashes, arrays, and variables for collected data
my $totec = 0; # total email count
my $trec = 0; # true email count (multiple recipients separated)
my @fsp; # first samples
my @lsp; # last samples
my %cnt; # per user count
my %raddr; # receiving addresses
my %slog; # sender logins
my %saddr; # sender addresses
my %mid; # exim mail ids
my %cwd; # current working directories
my %sub; # subjects
my %usercnt; #per user count
my %userraddr; #per user count recipients
my %m_rec; #per id recipients
my %bcnt; # bounces
my %bcnt_h; # hourly bounces
my %bcnt_rec; # bounced recipients
foreach my $file (@eximlogs) {
if (my $eximt = eximlogstart($file)) {
print "Processing '$file'.\n";
# makes sure the log contains the time we want to check
if ($startTime < $eximt) {
print "Start time pre-dates log, ";
if ($endTime < $eximt) {
print "checking next log.\n";
next;
} else {
print "but end time is present, checking anyways.\n";
}
}
# open file and parse lines
my $progress = -1;
my $filesize;
# this is totally a hack, but way faster than the pure perl way of doing it
my $fh;
if ($file =~ /^.*?\.gz$/) {
open($fh, "-|", "zcat " . $file);
my $gziplist=`gzip -l $file`;
$gziplist=~/.\n\s*\d*\s*(\d*)/;
$filesize=$1;
} else {
$fh = FileHandle->new("<$file");
$filesize = stat($file)->size
}
my $istty = (-t STDOUT);
my $pos = 0;
while (my $line = <$fh>) {
parseeximline(\$line, $startTime, $endTime, $fixedlogins_r, $ipaddr, \$totec, \$trec, \@fsp, \@lsp, \%cnt, \%raddr, \%slog,
\%saddr, \%mid, \%bcnt, \%bcnt_h, \%cwd, \%sub, \%usercnt, \%userraddr, \%m_rec, \%bcnt_rec);
$pos += length($line);
my $new_progress = int(($pos / $filesize) * 100);
if ($new_progress > $progress){ #prevent a billion slow i/o calls
$progress = $new_progress;
if ($istty) {
print "\r \rProgress: $progress%"; #replace prev line with new progress
} else {
if (($progress == 0) || ($progress % 10 == 0)) {
print "$progress%";
} else {
print ".";
}
}
}
}
$fh->close();
print "\n";
if ($startTime >= $eximt) {
last; # start time is in current log, we are done checking
}
}
}
return (\$totec, \$trec, \@fsp, \@lsp, \%cnt, \%raddr, \%slog, \%saddr, \%mid, \%bcnt, \%bcnt_h,
\%cwd, \%sub, \%usercnt, \%userraddr, \%bcnt_rec);
}
sub findlogs {
my ($directory, $rex) = @_;
my @files;
opendir(my $dh, $directory);
while(my $file = readdir($dh)) {
if ($file =~ /$rex/) {
push (@files, $directory.'/'.$file);
}
}
closedir($dh);
@files = sort {stat($b)->mtime <=> stat($a)->mtime} @files;
return \@files;
}
sub recordsample {
my ($fsp_r, $lsp_r, $time, $line_r) = @_;
my @sample = ($time, $line_r);
if ((scalar @{$fsp_r}) <= 0){
push @{$fsp_r}, \@sample;
} else {
if ($time <= ${${$fsp_r}[0]}[0]) {
unshift @{$fsp_r}, \@sample;
} elsif ($time >= ${${$fsp_r}[-1]}[0]) {
push @{$fsp_r}, \@sample;
} else {
for (my $i = 0; $i < (scalar @{$fsp_r}); $i++) {
if ($time <= ${${$fsp_r}[$i]}[0]) {
splice (@{$fsp_r}, $i, 0, \@sample);
last;
}
}
}
if ((scalar @{$fsp_r}) > 5){
pop @{$fsp_r};
}
}
if ((scalar @{$lsp_r}) <= 0){
push @{$lsp_r}, \@sample;
} else {
if ($time <= ${${$lsp_r}[0]}[0]) {
unshift @{$lsp_r}, \@sample;
} elsif ($time >= ${${$fsp_r}[-1]}[0]) {
push @{$lsp_r}, \@sample;
} else {
for (my $i = 0; $i < (scalar @{$lsp_r}); $i++) {
if ($time <= ${${$lsp_r}[$i]}[0]) {
splice (@{$lsp_r}, $i, 0, \@sample);
last;
}
}
}
if ((scalar @{$lsp_r}) > 5){
shift @{$lsp_r};
}
}
}
sub addemail {
my ($line_r, $time, $user, $sender, $totec_r, $trec_r, $fsp_r, $lsp_r, $cnt_r, $raddr_r, $slog_r,
$saddr_r, $mid_r, $id, $sub_r, $usercnt_r, $userraddr_r, $m_rec_r) = @_;
recordsample($fsp_r, $lsp_r, $time, $line_r);
${$line_r} =~ /^(.*(?:(?:from\s<[^>]*>)|(?:T=\"[^\"]*\"))\sfor\s)(.*)$/;
my @emails = split(/\s/, $2);;
foreach (@emails) {
unless($lowmem) {
${$raddr_r}{$_} += 1;
}
${$userraddr_r}{$user}{$_} += 1;
push (@{$m_rec_r->{$id}}, $_);
}
${$cnt_r}{strftime("%Y-%m-%d", CORE::localtime($time))}{localtime($time)->hour} += @emails;
${$usercnt_r}{$user}{strftime("%Y-%m-%d", CORE::localtime($time))}{localtime($time)->hour} += @emails;
${$trec_r} += @emails;
${$slog_r}{$user} += @emails;
unless($lowmem) {
if ($sender eq "<>") {
${$saddr_r}{"Blank Sender"} += @emails;
} else {
${$saddr_r}{$sender} += @emails;
}
}
${$totec_r}++;
push (@{${$mid_r}{$id}}, strftime("%Y-%m-%d", CORE::localtime($time)));
push (@{${$mid_r}{$id}}, localtime($time)->hour);
unless($lowmem) {
if (${$line_r} =~ /(T=\".*?(?<!\\)\"\s)/) {
${$sub_r}{$1} += @emails;
} else {
${$sub_r}{'Blank Subject'} += @emails;
}
}
}
sub addbounce {
my ($line_r, $id, $bounceid, $bcnt_r, $bcnt_h_r, $mid_r, , $m_rec_r, $bcnt_rec_r) = @_;
${$bcnt_r}{$id}++;
${$bcnt_h_r}{${$mid_r}{$bounceid}[0]}{${$mid_r}{$bounceid}[1]}++;
map {$bcnt_rec_r->{$_}++} @{$m_rec_r->{$bounceid}};
}
sub parseeximline {
my ($line_r, $startt, $endt, $flh_r, $ipaddr, $totec_r, $trec_r, $fsp_r, $lsp_r, $cnt_r, $raddr_r, $slog_r,
$saddr_r, $mid_r, $bcnt_r, $bcnt_h_r, $cwd_r, $sub_r, $usercnt_r, $userraddr_r, $m_rec_r, $bcnt_rec_r) = @_;
if (${$line_r} =~ /<=/) { # is this an outbound email?
if (${$line_r} =~ /^(\d{4})\-(\d{2})\-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s(\[\d{1,8}\]\s)?(\w{6}\-\w{6}\-\w{2})\s<=\s/gc) { # grab time and id
my $time = timegm($6, $5, $4, $3, $2 - 1, $1) - $offset;
my $id = $8;
if(($time >= $startt) & ($time <= $endt)) { # only count within the specified time range
if (${$line_r} =~ /\G((?:[^\s]*[\+@][^\s]*)|(?:<>))\s/gc) { # do we have a sender?
my $sender = $1;
if (${$line_r} =~ /\G(H=([^\s]*\s)?((\([^\(]*\)\s)?\[([^\]]*)\]))(:\d{1,5})?\s/gc) { # is this a remote user?
my $helo = $1;
my $ip = $5;
if (${$line_r} =~ /(A=(fixed|courier|dovecot)_(login|plain):(([^\+@%:\s]*)|([^\+@%:\s]*[\+@%:]([^\+@%:\s]*))))\s/) { # do we have a valid authenticator?
my $auth = $1;
my $euser;
if ($5) {
$euser = $5;
} elsif ($7) {
$euser = $7;
} else {
return;
}
if (exists ${$flh_r}{$euser}) {
addemail($line_r, $time, $auth, $sender, $totec_r, $trec_r, $fsp_r, $lsp_r, $cnt_r, $raddr_r, $slog_r,
$saddr_r, $mid_r, $id, $sub_r, $usercnt_r, $userraddr_r, $m_rec_r);
return;
} else {
return;
}
} else { # ipaddress tracking for imap/pop users goes here
if (exists ${$ipaddr}{$ip}) {
addemail($line_r, $time, $helo, $sender, $totec_r, $trec_r, $fsp_r, $lsp_r, $cnt_r, $raddr_r, $slog_r,
$saddr_r, $mid_r, $id, $sub_r, $usercnt_r, $userraddr_r, $m_rec_r);
return;
} elsif ($sender =~ /^(.*?)-bounces[\+@](.*?)$/) { # were we sent from a bounce address?
my $blist = $1;
my $bdomain = $2;
if (exists ${$flh_r}{$bdomain}) { # did the domain belong the the user?
if (${$line_r} =~ /id=mailman/) { # did the email belong to mailman?
addemail($line_r, $time, "Mailman:$blist\@$bdomain", $sender, $totec_r, $trec_r, $fsp_r, $lsp_r, $cnt_r, $raddr_r, $slog_r,
$saddr_r, $mid_r, $id, $sub_r, $usercnt_r, $userraddr_r, $m_rec_r);
return;
} elsif ($ip eq "127.0.0.1") { # are we a local email, if so, and we have a "bounces" address, we are probably mailman
addemail($line_r, $time, "Mailman:$blist\@$bdomain", $sender, $totec_r, $trec_r, $fsp_r, $lsp_r, $cnt_r, $raddr_r, $slog_r,
$saddr_r, $mid_r, $id, $sub_r, $usercnt_r, $userraddr_r, $m_rec_r);
}
else {
return;
}
} elsif($blist eq "mailman") {
if (${$line_r} =~ /T="([^\s]*)\s.*?\s([^\s]*)"/) { # catch generic mailman reminder messages
my $mdomains = $1;
my $mdomaine = $2;
if (exists ${$flh_r}{$mdomains}) { # does it belong to a domain we own?
addemail($line_r, $time, "Generic Mailman Reminder:$mdomains", $sender, $totec_r, $trec_r, $fsp_r, $lsp_r, $cnt_r, $raddr_r, $slog_r,
$saddr_r, $mid_r, $id, $sub_r, $usercnt_r, $userraddr_r, $m_rec_r);
} elsif (exists ${$flh_r}{$mdomaine}) {
addemail($line_r, $time, "Generic Mailman Reminder:$mdomaine", $sender, $totec_r, $trec_r, $fsp_r, $lsp_r, $cnt_r, $raddr_r, $slog_r,
$saddr_r, $mid_r, $id, $sub_r, $usercnt_r, $userraddr_r, $m_rec_r);
} else {
return;
}
} else {
return;
}
} else {
return;
}
} else {
return;
}
}
} elsif (${$line_r} =~ /\G(U=([^\s]*))\s/gc) { # is this a local user?
my $euser = $2;
my $login = $1;
if (exists ${$flh_r}{$euser}) {
if (${$line_r} =~ /id=[^\s]*squirrel@/) {
addemail($line_r, $time, 'Webmail', $sender, $totec_r, $trec_r, $fsp_r, $lsp_r, $cnt_r, $raddr_r, $slog_r,
$saddr_r, $mid_r, $id, $sub_r, $usercnt_r, $userraddr_r, $m_rec_r);
} else {
addemail($line_r, $time, $login, $sender, $totec_r, $trec_r, $fsp_r, $lsp_r, $cnt_r, $raddr_r, $slog_r,
$saddr_r, $mid_r, $id, $sub_r, $usercnt_r, $userraddr_r, $m_rec_r);
}
return;
} else {
return;
}
} elsif (${$line_r} =~ /\GR=(\w{6}\-\w{6}\-\w{2})\s/gc) { # is this a returned mail?
my $bounceid = $1;
if (exists ${$mid_r}{$bounceid}) { # is it one that we sent?
addbounce($line_r, $id, $bounceid, $bcnt_r, $bcnt_h_r, $mid_r, $m_rec_r, $bcnt_rec_r);
return;
} else {
return;
}
}
}
}
}
} elsif (${$line_r} =~ /cwd=/) { # is this a cwd line?
if (${$line_r} =~ /^(\d{4})\-(\d{2})\-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\scwd=(\/home\d?\/([^\/\s]*)([^\s]*)?)\s/gc) { # grab time and path
my $time = timegm($6, $5, $4, $3, $2 - 1, $1) - $offset;
my $cwdp = $7;
my $cuser = $8;
if(($time >= $startt) & ($time <= $endt)) { # only count within the specified time range
if (exists ${$flh_r}{$cuser}) {
${$cwd_r}{$cwdp}++;
} else {
return;
}
}
}
}
}
sub commify { #commify (add commas to a number in a string)
my $text = reverse $_[0];
$text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
return scalar reverse $text
}
sub printtotals {
my ($trec, $raddr_r, $bcnt_r, $bcnt_rec_r) = @_;
my $percent = 0;
if ($trec > 0) {
$percent = (scalar(keys %{$bcnt_r})/$trec)*100;
}
print "User sent approximately ".commify($trec)." messages to ".commify(scalar(keys %{$raddr_r}))." unique recipients.\n";
print "There were ".scalar(keys %{$bcnt_r})." bounces on ".scalar(keys %{$bcnt_rec_r})." unique addresses, ".int($percent)." percent of the emails sent.\n\n";
}
sub formatsample {
my ($sample) = @_;
my $fsample;
if ($sample =~ /^(.*(?:(?:from\s<[^>]*>)|(?:T=\"[^\"]*\"))\sfor\s)(.*)$/) {
my @emails = split(/\s/, $2);
if (@emails > 5) {
$fsample = $1;
my $i = 0;
while ($i < 5) {
$fsample = $fsample."$emails[$i] ";
$i++;
}
$fsample = $fsample."... ".(@emails - 5)." additional email addresses removed.\n";
} else {
$fsample = $sample;
}
} else {
$fsample = $sample;
}
return $fsample;
}
sub printsamples {
my ($fsp_r, $lsp_r) = @_;
print "Selected email samples:\n";
print "-----------------------\n\n";
print "First 5 Entries:\n\n";
foreach my $samp_r (@{$fsp_r}) {
my $samp = ${${$samp_r}[1]};
print formatsample($samp);
}
print "\n";
print "Last 5 Entries:\n\n";
foreach my $samp_r (@{$lsp_r}) {
my $samp = ${${$samp_r}[1]};
print formatsample($samp);
}
print "\n";
}
sub pnbs {
my ($text, $size) = @_;
# return padleft($text, $size, "\xc2\xa0"); # unicode non breaking space
return padleft($text, $size, ' '); # normal space
}
sub padleft {
my ($text, $size, $fill) = @_;
if (($size - length($text)) <= 0) {
return $text;
} else {
return ($fill x ($size - length($text))).$text;
}
}
sub printhourly {
my ($cnt_r, $bcnt_h_r, $usercnt_r, $slog_r, $userraddr_r) = @_;
my $indthresh = 500; # threshold for displaying domain count
print "Hourly mail volume for the entire account:\n\n";
for my $d (sort {$a cmp $b} keys %{$cnt_r}) { #print numbers of emails sent, grouped into days and hours
print "$d\n";
print "-" x30 . "\n";
print pnbs("Hour",4).pnbs("Volume",10).pnbs("Bounces",10).pnbs("%",6)."\n";
print "-" x30 . "\n";
for my $h (sort {$a <=> $b} keys %{${$cnt_r}{$d}}) {
my $chour = ${$cnt_r}{$d}{$h};
my $cbounce = 0;
if (exists ${$bcnt_h_r}{$d}{$h}) {
$cbounce = ${$bcnt_h_r}{$d}{$h};
}
my $percent;
if ($chour <= 0) {
$percent = 100;
} else {
$percent = ($cbounce/$chour)*100;
}
print pnbs($h,4).pnbs(commify($chour),10).pnbs(commify($cbounce),10).pnbs(int($percent),6)."\n";
}
print "\n";
}
my %udomains;
my %udomainrecs;
for my $u (keys %{$usercnt_r}) {
my $udomain;
if ($u =~ /(^.*?[\+@](.*?)$)/) {
$udomain = $2;
} elsif ($u =~ /(^U=(.*?)$)/) {
$udomain = $1;
} else {
next; # this really shouldnt ever happen, but we should capture it anyways
}
for my $d (keys %{${$usercnt_r}{$u}}) {
for my $h (keys %{${$usercnt_r}{$u}{$d}}) {
$udomains{$udomain}{$d}{$h} += ${$usercnt_r}{$u}{$d}{$h};
}
}
for my $r (keys %{${$userraddr_r}{$u}}) {
$udomainrecs{$udomain}{$r} = ${$userraddr_r}{$u}{$r};
}
}
if (scalar keys %udomains > 1) { # don't bother with the excess hourly display if there is only one user sending mail
for my $u (sort {$udomains{$a} <=> $udomains{$b}} keys %udomains) {
my $total = 0;
for my $d (keys %{$udomains{$u}}) { # total up emails sent
for my $h (keys %{$udomains{$u}{$d}}) {
$total += $udomains{$u}{$d}{$h};
}
}
if ($total > $indthresh) { # if the account has sent more than the threshold
print "\nThe '$u' account/domain was detected as sending large amounts of email.\n";
print "The account/domain sent ".commify($total)." emails to ".commify((scalar (keys %{$udomainrecs{$u}})))." unique recipients. Displaying hourly mail:\n\n";
for my $d (sort {$a cmp $b} keys %{$udomains{$u}}) { #print numbers of emails sent, grouped into days and hours
print "$d\n";
print "-" x14 . "\n";
print pnbs("Hour",4).pnbs("Volume",10)."\n";
print "-" x14 . "\n";
for my $h (sort {$a <=> $b} keys %{$udomains{$u}{$d}}) {
print pnbs($h,4).pnbs(commify($udomains{$u}{$d}{$h}),10)."\n";
}
print "\n";
}
}
}
}
}
sub printsendaddr {
my ($saddr_r) = @_;
if (%{$saddr_r}) { #only print out email addresses if there are any (there should be)
print "Email addresses sent from:\n";
print "--------------------------\n";
my @s = sort {int (${$saddr_r}{$b}) <=> int(${$saddr_r}{$a})} keys %{$saddr_r};
if ($terse && (scalar(@s) > 15)) { # trim long displays
for (my $i = 0; $i < 15; $i++) {
my $c = shift @s;
print "$c: " . commify(${$saddr_r}{$c}) . "\n";
}
print "\nThere were ".scalar(@s)." additional sender addresses trimmed.\n";
} else {
for my $c (@s) {
print "$c: " . commify(${$saddr_r}{$c}) . "\n";
}
}
print "\n";
}
}
sub printsendlog {
my ($slog_r) = @_;
if (%{$slog_r}) { #only print out logins if there are any
print "Logins used to send mail:\n";
print "-------------------------\n";
my @l = sort {int (${$slog_r}{$b}) <=> int(${$slog_r}{$a})} keys %{$slog_r};
if ($terse && (scalar(@l) > 15)) { # trim long displays
my %new_slog;
for my $c (@l) { # collapse randomized HELO strings
if ($c =~ /(H=([^\s]*\s)?((\([^\(]*\)\s)?\[([^\]]*)\]))(:\d{1,5})?/) {
$new_slog{"H=(...) [$5]"} += ${$slog_r}{$c};
} else {
$new_slog{$c} += ${$slog_r}{$c};
}
}
@l = sort {int ($new_slog{$b}) <=> int($new_slog{$a})} keys %new_slog;
if (scalar(@l) > 15) { # trim long displays
for (my $i = 0; $i < 15; $i++) {
my $c = shift @l;
print "$c: " . commify($new_slog{$c}) . "\n";
}
print "\nThere were ".scalar(@l)." additional logins trimmed.\n";
} else {
for my $c (@l) {
print "$c: " . commify($new_slog{$c}) . "\n";
}
}
} else {
for my $c (@l) {
print "$c: " . commify(${$slog_r}{$c}) . "\n";
}
}
print "\n";
}
}
sub printcwd {
my ($cwd_r) = @_;
if (%{$cwd_r}) { #only print out cwd stats if there are any
print "Current working directories:\n";
print "----------------------------\n";
for my $c (sort {int (${$cwd_r}{$b}) <=> int(${$cwd_r}{$a})} keys %{$cwd_r}) {
print "$c: " . commify(${$cwd_r}{$c}) . "\n";
}
print "\n";
}
}
sub printsubs {
my ($subs_r) = @_;
if (%{$subs_r}) { #only print out subjects if there are any (there should be)
print "Top subjects:\n";
print "-------------\n";
# sort subjects
my @subss = sort {int (${$subs_r}{$b}) <=> int(${$subs_r}{$a})} keys %{$subs_r};
if (scalar @subss <= 10) {
foreach my $sub (@subss) {
print "$sub: ${$subs_r}{$sub}\n";
}
} else {
for (my $i = 0; $i < 10; $i++) {
print "$subss[$i]: ${$subs_r}{$subss[$i]}\n";
}
}
print "\n";
print "Total number of discrete subjects: " . scalar keys(%{$subs_r}) . "\n\n";
}
}
sub printrecaddr {
my ($raddr_r) = @_;
if (%{$raddr_r}) { #only print out email addresses if there are any (there should be)
my @k = sort {int (${$raddr_r}{$b}) <=> int(${$raddr_r}{$a})} keys %{$raddr_r};
print "Random recipient addresses:\n";
print "---------------------------\n";
if (scalar @k <= 10) {
foreach my $addr (@k) {
print "$addr\n";
}
} else {
for (my $i = 0; $i < 10; $i++) {
print $k[rand @k] . "\n";
}
}
print "\n";
print "Top recipients:\n";
print "---------------\n";
if (scalar @k <= 10) {
foreach my $addr (@k) {
print "$addr: ${$raddr_r}{$addr}\n";
}
} else {
for (my $i = 0; $i < 10; $i++) {
print "$k[$i]: ${$raddr_r}{$k[$i]}\n";
}
}
print "\n";
}
}
sub printexim {
my ($saddr_r) = @_;
my @queue = `exim -bpr`;
my $queuemails = 0;
foreach (@queue) {
$_ =~ s/^\s+|\s+$//g; # kill whitespace and newlines
if (exists ${$saddr_r}{$_}) {
$queuemails++;
}
}
print "Emails currently in queue:\n";
print "--------------------------\n";
print "User: $queuemails, Total: ";
print `exim -bpc`;
print "\n";
}
sub printtimerange {
my ($startTime, $endTime) = @_;
my @monthsArr = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
my ($psec,$pmin,$phour,$pday,$pmon,$pyear) = CORE::localtime($startTime);
my ($sec,$min,$hour,$day,$mon,$year) = CORE::localtime($endTime);
printf "Mail Log Parsed from $monthsArr[$pmon] $pday, %d %02d:%02d:%02d to $monthsArr[$mon] $day, %d %02d:%02d:%02d\n\n", ($pyear + 1900), $phour, $pmin, $psec, ($year + 1900), $hour, $min, $sec;
}
sub maillogstart {
my ($file) = @_;
my %monthsRev = ("Jan"=>1, "Feb"=>2, "Mar"=>3, "Apr"=>4, "May"=>5, "Jun"=>6, "Jul"=>7, "Aug"=>8, "Sep"=>9, "Oct"=>10, "Nov"=>11, "Dec"=>12);
my $fh = new FileHandle;
$fh->open("<$file");
my $fhp;
if ($file =~ /^.*?\.gz$/) {
$fhp = new IO::Uncompress::Gunzip $fh;
} else {
$fhp = $fh;
}
my $time;
while(my $line = <$fhp>) {
if ($line =~ /((\w{3})\s{1,2}(\d{1,2})\s(\d{2}):(\d{2}):(\d{2}))/) {
$time = timelocal($6, $5, $4, $3, $monthsRev{$2} - 1, localtime->year() + 1900);
last;
}
}
$fh->close();
return $time;
}
sub processmaillogs {
my ($searchusers_r, $fixedlogins_r, $startTime, $endTime) = @_;
my @searchusers = @{$searchusers_r};
my %monthsRev = ("Jan"=>1, "Feb"=>2, "Mar"=>3, "Apr"=>4, "May"=>5, "Jun"=>6, "Jul"=>7, "Aug"=>8, "Sep"=>9, "Oct"=>10, "Nov"=>11, "Dec"=>12);
my $year = localtime->year() + 1900;
# specify logs to search
my @maillogs = @{findlogs('/var/log', 'maillog((-\d{8})|(\.\d))?(\.gz)?')};
# setup hashes, arrays, and variables for collected data
my %ipaddr; # ip addresses logging in via POP/IMAP
# grab the server's own ip address
my $myip = `hostname -i`;
chomp($myip);
foreach my $file (@maillogs) {
if (my $eximt = maillogstart($file)) {
print "Processing '$file'.\n";
# makes sure the log contains the time we want to check
if ($startTime < $eximt) {
print "Start time pre-dates log, ";
if ($endTime < $eximt) {
print "checking next log.\n";
next;
} else {
print "but end time is present, checking anyways.\n";
}
}
# open file and parse lines
my $progress = -1;
my $filesize;
# this is totally a hack, but way faster than the pure perl way of doing it
my $fh;
if ($file =~ /^.*?\.gz$/) {
open($fh, "-|", "zcat " . $file);
my $gziplist=`gzip -l $file`;
$gziplist=~/.\n\s*\d*\s*(\d*)/;
$filesize=$1;
} else {
$fh = FileHandle->new("<$file");
$filesize = stat($file)->size
}
my $istty = (-t STDOUT);
my $pos = 0;
while (my $line = <$fh>) {
parsemailline(\$line, $startTime, $endTime, \%monthsRev, $year, $fixedlogins_r, \%ipaddr, $myip);
$pos += length($line);
my $new_progress = int(($pos / $filesize) * 100);
if ($new_progress > $progress){ #prevent a billion slow i/o calls
$progress = $new_progress;
if ($istty) {
print "\r \rProgress: $progress%"; #replace prev line with new progress
} else {
if (($progress == 0) || ($progress % 10 == 0)) {
print "$progress%";
} else {
print ".";
}
}
}
}
$fh->close();
print "\n";
if ($startTime >= $eximt) {
last; # start time is in current log, we are done checking
}
}
}
return (\%ipaddr);
}
sub parsemailline {
my ($line_r, $startTime, $endTime, $monthsRev_r, $year, $fixedlogins_r, $ipaddr_r, $myip) = @_;
if (${$line_r} =~ /((\w{3})\s{1,2}(\d{1,2})\s(\d{2}):(\d{2}):(\d{2})).*?Login: /gc) { # is this a login?
my $logTime = timegm($6, $5, $4, $3, ${$monthsRev_r}{$2} - 1, $year) - $offset;
if(($logTime >= $startTime) & ($logTime <= $endTime)) { # only count within the specified time range
if (${$line_r} =~ /\Guser=<((.*?[\@+])?([^>]*))>.*?rip=([^,]*),/gc) { # do we have a user?
my $user = $3;
my $ip = $4;
if (($ip ne "127.0.0.1") && ($ip ne $myip)) { # ignore localhost entries
if (exists ${$fixedlogins_r}{$user}) {
${$ipaddr_r}{$ip}++;
}
}
}
}
}
}
sub pseudoui {
my ($user) = @_;
my $cuserpath = "/var/cpanel/users";
my $netpath = "/etc/sysconfig/network";
my $hostname = `hostname`;
# my $hostname;
my $owner = undef;
my $domain = undef;
open(NETWORK, $netpath);
while(my $line = <NETWORK>) {
if ($line =~ m/HOSTNAME=([a-z0-9]*)/) {
$hostname = $1;
last;
}
}
close(NETWORK);
if ($user ne "root") {
open(CUSERS, "$cuserpath/$user");
while(my $line = <CUSERS>) {
if ($line =~ m/OWNER=([a-z0-9]*)/) {
$owner = $1;
last;
}
}
close(CUSERS);
open(CUSERS, "$cuserpath/$user");
while(my $line = <CUSERS>) {
if ($line =~ m/DNS=(.*?)$/) {
$domain = $1;
last;
}
}
close(CUSERS);
}
if ($owner) {
if (!($owner eq "root") && !($owner eq $user)) {
print "Mail Report: $hostname: $owner($user)\n\n\n";
} else {
print "Mail Report: $hostname: $user\n\n\n";
}
} else {
print "Mail Report: $hostname\n\n\n";
}
print " Server: $hostname\n";
if ($domain) {
print " Domain: $domain\n";
}
print " User: $user\n";
if ($owner) {
if (!($owner eq "root") && !($owner eq $user)) {
print " Owner: $owner\n";
}
}
}
sub get_homedir {
my ($user) = @_;
my @pwent = getpwnam($user);
return $pwent[7];
}
EOF
)"
# Print the Perl script result
echo "$perl_result" | sed -e 's/T=//g' -e 's/"//g' -e 's/\t//g'
}
function finddiskspace() {
if [ "$(df -h | awk 'FNR == 2 {print $5}' | sed 's/%$//')" -gt "25" ]; then
echo ""
echo -n "Warning! Disk space usage is higher than 25%!"
echo ""
echo ""
df -h | awk '$NF=="/"{printf "Disk Usage: %d/%dGB (%s)\n", $3,$2,$5}'
echo ""
echo ""
echo -n "Searching for backups or files larger than 250M on $(hostname -f): "
echo ""
echo ""
echo -n "Backups: "
echo ""
echo ""
du -shc /backup///
echo ""
echo ""
echo -n "File Usage: "
echo ""
echo ""
du -shc $(find /home/ -size +250M -print 2>/dev/null) | grep total
echo ""
echo ""
echo "Total Usage (Files + Backup): " && echo "" && du -shc $(find /home/ /backup -size +250M -print 2>/dev/null)
echo ""
echo ""
else
echo ""
echo ""
echo -n "Disk space check is less than 25%"
echo ""
echo ""
df -h | awk '$NF=="/"{printf "Disk Usage: %d/%dGB (%s)\n", $3,$2,$5}'
echo ""
echo ""
fi
}
function pass-security(){
username=$(awk -F'@' '{print $1}' <<< $1)
domain=$(awk -F'@' '{print $2}' <<< $1)
cPuser=$(/scripts/whoowns $domain)
enctype="{SHA512-CRYPT}"
hash=$(cat /home/$cPuser/etc/$domain/shadow | grep $username | awk -F':' '{print $2}')
encpass="{SHA512-CRYPT}$hash"
doveadm pw -t $encpass -p $2
}
function listfunctions() {
echo -e "${CYAN}apache-stats ${NC}-- Provides a comprehensive listing of all current Apache Workers across all domains hosted on the VPS. Useful for troubleshooting limits with MaxRequestWorkers as well as identifying DDoS attack targets."
echo -e "${CYAN}zone ${NC}-- Displays all zone entries for given domain, usage: zone domain.tld"
echo -e "${CYAN}blocks ${NC}-- Displays all blocks in lfd.log for today's date."
echo -e "${CYAN}bots ${NC}-- This function performs a search across all of the domlogs for entries marked for the current date related to bot activity and outputs information useful to determining if perhaps a robots.txt is needed."
echo -e "${CYAN}cfallow ${NC}-- Automatically downloads and adds all of CloudFlare's IPv4 Addresses into CSF."
echo -e "${CYAN}docroot ${NC}-- Usage: docroot domain.tld, provides document root"
echo -e "${CYAN}ddos ${NC}-- DDoS log analyzer, usage: ddog /home/user/accesslogs/log_file"
echo -e "$(bad2 "enable-root -- CAUTION: This will enable root access over SSH with password authentication. Advise clients of the pros/cons of this feature before enabling.")"
echo -e "${CYAN}errors ${NC}-- This is an easy to use tool that provides all error output from error_log files for the current day run in public_html for best effectiveness."
echo -e "${CYAN}exim-security ${NC}-- Provides exim security protocols allowed and cipher suite."
echo -e "${CYAN}hack ${NC}-- Searches the domlogs for signs of brute force via xmlrpc.php, wp-login.php, and admin-ajax.php"
echo -e "${CYAN}install-softaculous ${NC}-- Auto-launches Will C.'s Softaculous installation script."
echo -e "${CYAN}findbigdirs ${NC}-- Reports any big directories within /home/*/public_html and /home/*/mail/"
echo -e "${CYAN}fixlicense ${NC}-- Fixes issues with cpanel licensces"
echo -e "${CYAN}ggnull ${NC}-- Usage: ggnull IP_Address, null routes IP Address provided."
echo -e "${CYAN}ggpaste ${NC}-- Provides a URL of the output data, used either in | or >"
echo -e "$(good2 "ggexit -- Closes the session properly as the utility creates a dual bash session environment.")"
echo -e "${CYAN}lsdomains ${NC}-- Lists all domain names hosted on the VPS."
echo -e "${CYAN}lsforwards ${NC}-- Lists all mail forwarders on the VPS"
echo -e "${CYAN}phpusers ${NC}-- Provides information regarding each cPanel user and which PHP version they are configured to use."
echo -e "${CYAN}robotstxt ${NC}-- Searches throughout all the user public_html for robots.txt and reports directives."
echo -e "$(bad2 "sec-disable -- CAUTION: This disables Security Questions and MUST be re-enabled once you complete your work.")"
echo -e "${CYAN}sec-enable ${NC}-- CAUTION: Do not enable this unless the client had it enabled previously and you disabled to service the server."
echo -e "${CYAN}summary ${NC}-- This run's the GG Summary Script for quoting server migrations."
echo -e "${CYAN}wpfunctions ${NC}-- This provides a comprehensive list of functions pertaining to WordPress."
}
function spamcheck(){
# Email Report
#By Robert J
echo ""
echo -n "==================EMAIL REPORT====================="
echo ""
echo ""
echo -n "===========$(date)============"
echo ""
echo ""
echo -n "Total emails in exim queue: " && exim -bpc
echo ""
echo -n "Total frozen emails in exim queue: " && exiqgrep -iz | wc -l
echo ""
exim -bp | exiqsumm | egrep -v "\-\-|Volume|^$" | sort -bg | awk '{print "Volume: " $1 " \t Domain: " $5}'
echo ""
echo ""
if [ -d /usr/local/cpanel ];then
echo "Checking for relay entries within LFD log files."
echo ""
echo "$(grep -i relay /var/log/lfd.log)"
echo ""
echo "Checking for high volume dovecot logins for potential compromised accounts."
echo ""
echo "$(grep -Po '(?<=dovecot_(plain|login):)\S*' /var/log/exim_mainlog | sort | uniq -c | sort -n | tail)"
echo ""
echo ""
echo ""
eximstats /var/log/exim_mainlog | head -11 && eximstats /var/log/exim_mainlog | grep -A 5 rejection | sed '/sending/d'
echo ""
echo ""
echo -n "Blacklist Check URL: " && echo -n "https://mxtoolbox.com/SuperTool.aspx?action=blacklist%3A$(hostname -i)"
echo ""
echo ""
echo ""
echo -n "=====EXIM LOG SAMPLES====="
echo ""
echo ""
tail -25 /var/log/exim_mainlog
echo ""
echo ""
else
echo "Checking for relay entries within LFD log files."
echo ""
echo "$(grep -i relay /var/log/lfd.log)"
echo ""
echo "Checking for high volume dovecot logins for potential compromised accounts."
echo ""
echo "$(grep -Po '(?<=dovecot_(plain|login):)\S*' /var/log/exim/main_log | sort | uniq -c | sort -n | tail)"
echo ""
echo ""
eximstats /var/log/exim/main_log | head -11 && eximstats /var/log/exim/main_log | grep -A 5 rejection | sed '/sending/d'
echo ""
echo ""
echo -n "Blacklist Check URL: " && echo -n "https://mxtoolbox.com/SuperTool.aspx?action=blacklist%3A$(hostname -i)"
echo ""
echo ""
echo ""
echo -n "=====EXIM LOG SAMPLES====="
echo ""
echo ""
tail -25 /var/log/exim/main_log
echo ""
echo ""
fi
}
function dspace() {
python2 << END
import os
import subprocess
import shlex
import sys
#paths to check
bpath = '/backup/'
hpath = '/home/'
plist = list()
max = 200
def run(cmd):
proc=subprocess.Popen(shlex.split(cmd),stdout=subprocess.PIPE)
out,err=proc.communicate()
return str(out)
def gsize(num):
if int(num) > 1024:
gbsize = num / float(1024)
if str(gbsize).count('.') >= 1:
gb = str(gbsize).split(".")
size = gb[0] + "." + gb[1][:2] + "G"
else:
size = str(num) + "M"
return size
def filter(input):
fsize,fname = input.split("\t")
if fsize >= 1024:
msize = int(fsize) / 1024
if msize >= max:
fname = fname.lstrip()
fname = fname.rstrip()
if fname.count('/') >=4:
hsize = gsize(msize)
print hsize + " " + fname
if fname.count('/') <= 3:
plist.append(fname)
def list_files(startpath):
for root, dirs, files in os.walk(startpath):
level = root.replace(startpath, '').count(os.sep)
indent = ' ' * 4 * (level)
tprint = '{}{}/'.format(indent, os.path.basename(root))
if tprint != '/':
if tprint != 'virtfs/':
if os.path.isdir(startpath + tprint):
filter(run('du -s ' + startpath + tprint))
subindent = ' ' * 4 * (level + 1)
def chkdir(dir):
if os.listdir(dir):
#print 'Output from ' + dir
list_files(dir)
else:
print dir + ' is empty'
def subdir():
for p in plist:
chkdir(p)
def bigf():
print "Listing of files over " + str(max) + "MB"
for p in plist:
#print p
g = run ('find ' + p + ' -type f -size +' + str(max) + '000k -exec ls -lh {} \;')
#print g
gsplit = g.split('\n')
#print str(len(gsplit))
dl = len(gsplit)
d = 1
for r in gsplit:
if d < dl:
rsplit = r.split(' ')
if len(rsplit) > 8:
c = 0
for i in rsplit:
if c == 4:
lt = i
if c >= 7:
lt = lt + " " + i
c += 1
print lt
else:
print rsplit[4] + " " + rsplit[7]
d += 1
print "Looking for directories over " + str(max) + "MB"
print "Checking for large directories within " + bpath + " " + hpath
chkdir(bpath)
chkdir(hpath)
subdir()
print ""
bigf()
END
}
function zone(){
awk '$1 ~ /[^;]/' /var/named/$@.db
}
function checkssl(){
certificate=$(echo | openssl s_client -showcerts -servername $1 -connect $1:443 2>/dev/null | openssl x509 -inform pem -noout -text | grep -E 'Issuer|Not After|DNS')
echo "Domains: $(echo "$certificate" | awk -F'DNS:' '{print $2 $3 $4}' | grep '*')"
echo "Issuer: $(echo "$certificate" | awk -F', O=' '{print $2}' | awk -F', CN' '{print $1}')"
echo "Expires: $(echo "$certificate" | awk -F'Not After : ' '{print $2}' | sed -e 's/^[[:space:]]*//' | grep 'GMT')"
}
function wpfunctions(){
curl -s https://gist.githubusercontent.com/markjaquith/4487609/raw/a9bd6282620c7dada3cff9e8dee2bdf5cdc6b163/gistfile1.txt | tail -n +2 | head -n -2
echo -e "${M}wpaudit ${NC}-- Provides an audit of a WP install, ran as root within the installation directory includes siteurl, version, and
summary of plugin and theme based on number of installed, updates pending, and inactive."
echo -e "${M}wpthemelist ${NC}-- Provides standard output of wp-cli wp theme list, but as root without security risks."
echo -e "${M}wpplugininfo ${NC}-- Provides a brief description of a given plugin, must use the name as provided via wp-cli or WordPress.org."
echo -e "${M}wppluginlist ${NC}-- Provides standard output of wp-cli wp plugin list, but as root without security risks."
echo -e "${M}wpsecurity ${NC}-- Provides a list of any/all installations detected of WordPress installs containing WordFence and WP-Cerber."
}
#WP Plugin info
function wpplugininfo(){
content=$(curl -s https://wordpress.org/plugins/$1/)
length=$(echo "$content" | wc -l)
begin=$(echo "$content" | grep -n '<script type="application/ld+json">' -m 1 | cut -f1 -d:)
string=$(echo "$content" | tail -n $((length - begin + 1)))
end=$(echo "$string" | grep -n '</script>' -m 1 | cut -f1 -d:)
name=$(echo "$string" | head -n $end | grep name | awk -F': "' '{print $2}' | awk -F'",' '{print $1}')
description=$(echo "$string" | head -n $end | grep description | awk -F': "' '{print $2}' | awk -F'",' '{print $1}')
version=$(echo "$string" | head -n $end | grep softwareVersion | awk -F': "' '{print $2}' | awk -F'",' '{print $1}')
modified=$(echo "$string" | head -n $end | grep dateModified | awk -F': "' '{print $2}' | awk -F'",' '{print $1}')
echo $name | sed s/'WordPress.org'//g
echo $description
echo "Version: $version"
echo "Last updated: $(date -d"$modified" +%B" "%d", "%Y)"
}
#WP Plugin List
function wppluginlist(){
cpwd=$(pwd)
runuser -l $(stat -c %U .) -c "cd $cpwd; wp plugin list"
}
#WP Thee List
function wpthemelist(){
cpwd=$(pwd)
runuser -l $(stat -c %U .) -c "cd $cpwd; wp theme list"
}
# Function to create a random admin user
generate_random_string() {
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w "${1:-10}" | head -n 1
}
function wpcreateadmin() {
local wp_url=$(wp option get siteurl --allow-root)
# Generate random username and password
local username=$(generate_random_string 8)
local password=$(generate_random_string 12)
local cpwd=$(pwd)
# Suppress error output temporarily
exec 3>&2 # Save current stderr to file descriptor 3
exec 2> /dev/null # Redirect stderr to /dev/null (suppress errors)
# Execute the WP-CLI command to create the admin user
makeuser=$(runuser -l $(stat -c %U .) -c "cd $cpwd && wp user create $username --allow-root '${username}@ggsupport.com' \
--role=administrator \
--user_pass='$password' \
--display_name='GreenGeeks Temporary Admin User' --path='$cpwd'")
# Restore stderr to its original state
exec 2>&3 # Restore stderr from file descriptor 3
exec 3>&- # Close file descriptor 3 (cleanup)
# Return username, password, and WordPress login URL
echo "Username: $username"
echo "Password: $password"
echo "WordPress Login URL: ${wp_url}/wp-login.php"
# Schedule deletion of the user after 30 minutes
echo "/usr/local/bin/wp user delete $username --path='$cpwd' --yes --allow-root" | at now + 30 minutes
}
#WP Audit
function wpaudit(){
cpwd=$(pwd)
siteurl=$(runuser -l $(stat -c %U .) -c "cd $cpwd; wp option get siteurl")
version=$(runuser -l $(stat -c %U .) -c "cd $cpwd; wp core version")
plugins="$(runuser -l $(stat -c %U .) -c "cd $cpwd; wp plugin list")"
themes="$(runuser -l $(stat -c %U .) -c "cd $cpwd; wp theme list")"
echo "WP siteurl: $siteurl"
echo "WP filepath: $cpwd"
echo "WP version: $version"
echo "WP themes: $(echo "$themes" | tail -n +2 | wc -l) total, $(echo "$themes" | grep available | wc -l) updates, $(echo "$themes" | grep inactive | wc -l) inactive"
echo "WP plugins: $(echo "$plugins" | tail -n +2 | wc -l) total, $(echo "$plugins" | grep available | wc -l) updates, $(echo "$plugins" | grep inactive | wc -l) inactive"
}
#GGLoop
function ggloop(){
c=0
for i in "$@"
do
c=$((c+1))
if [ $c != 1 ]; then
cmd="$cmd $i"
fi
done
while read p; do
rcmd="$(echo $cmd | sed "s/\%v/$p/g")"
$rcmd
done < $1
}
# ggpaste Utility
# @return $paste_url
function ggpaste() {
if [ ! -z $2 ]
then
curl --header "GGAUTH: ggpaste_259gag235" --form t=$1 --form file=@$2 https://paste.websitehostserver.net
else
curl --header "GGAUTH: ggpaste_259gag235" --form t=$1 --form file=@- https://paste.websitehostserver.net
fi
}
#Null Router
function ggnull(){
route add -host $1 reject
}
#Whitelist CloudFlare
function cfallow(){
IPS=`curl -s https://www.cloudflare.com/ips-v4`
for ip in ${IPS}; do
csf -a $ip
done
csf -r
}
#Mass CloudFlare
function masscf(){
IPS=`curl -s https://www.cloudflare.com/ips-v4`
for ip in ${IPS}; do
csf -$1 $ip
done
#csf -r
}
#Get DDoS logs
function ddos() {
domain=$1
echo "Top URLs Requested:"
grep "$(date +%d/%b/%Y)" $domain | awk '{print $7}' | sort | uniq -c | sort -r | awk '$1>100'
echo "Top IP Addresses:"
grep "$(date +%d/%b/%Y)" $domain | awk '{print $1}' | sort | uniq -c | sort -r | awk '$1>100'
echo "Top User Agents:"
grep "$(date +%d/%b/%Y)" $domain | awk -F'"' '{print $6}' | grep -E '^.{50,}$' | sort | uniq -c | sort -r | head -n 10
}
######### RCTMP RIPPED FUNCTIONS NEED TO REWRITE SOME AND DOCUMENT
function hack() {
D=$(date +%d)
M=$(date +%b)
Y=$(date +%Y)
echo "Checking for xmlrpc.php brute force attacks.."
echo "$(grep -H $D/$M/$Y /usr/local/apache/domlogs/* 2>/dev/null |grep 'POST /xmlrpc.php'|cut -d: -f1|sort|uniq -c)"
echo ""
echo "Checking for wp-login.php brute force attacks.."
echo "$(grep -H $D/$M/$Y /usr/local/apache/domlogs/* 2>/dev/null |grep 'POST /wp-login.php'|cut -d: -f1|sort|uniq -c)"
echo ""
echo "Checking for admin-ajax.php abuse.."
echo "$(grep -H $D/$M/$Y /usr/local/apache/domlogs/* 2>/dev/null |grep 'POST /admin-ajax.php'|cut -d: -f1|sort|uniq -c)"
}
function bots() {
D=$(date +%d)
M=$(date +%b)
Y=$(date +%Y)
echo "Checking for bot traffic.."
echo "$(grep -H $D/$M/$Y /usr/local/apache/domlogs/* 2>/dev/null |grep 'Bot'|cut -d: -f1|sort|uniq -c)"
}
function blocks() {
D=$(date +%d)
M=$(date +%b)
Y=$(date +%Y)
grep "$M $D" /var/log/lfd.log | grep Blocked
}
function docroot(){
grep -E "^${1}: " /etc/userdatadomains|awk -F'==' '{print $5}'
}
function lsdomains() {
grep -E "==(addon|main)==" /etc/userdatadomains|cut -d: -f1|sort | xargs -i sh -c 'echo {} " " $(/scripts/whoowns {})'
}
function lsforwards(){
grep "=> .*@.*@.*lookuphost" /var/log/exim_mainlog | awk '{print $6,$5}' |sed 's/(//g;s/)//g;s/<//g;s/>//g'|awk '$2 ~ "@"'| sort | uniq -c | sort -n
}
function findbigdirs() {
if [[ $NCP == 0 ]];then
tmpLIST="/tmp /home/*/public_html /home/*/mail"
else
tmpLIST="/tmp /home/*/public_html"
fi
find $tmpLIST -xdev -printf '%h\n' | sort | uniq -c | awk '$1 >= 800' | sort -k 1 -rn
}
function robotstxt() {
find /home/ -name robots.txt -type f | xargs grep -n delay | head $(awk -F':' '{print $1 " -n " $2}') | grep -v "#"
}
function wpsecurity(){
echo "Looking for installations of WP-Cerber"
find /home/ -name wp-cerber -type d
echo ""
echo "Looking for installations of Wordfence"
find /home/ -name wordfence -type d
}
######### END
#Security Questions Functions
function sec-enable() {
case $secpol in
"N") echo "Security Questions is not setup." ;;
"1") echo "Security Questions already enabled." ;;
"0")
echo "Security Questions have been enabled."
sed -i 's/SecurityPolicy::SourceIPCheck=0/SecurityPolicy::SourceIPCheck=1/g' /var/cpanel/cpanel.config
/scripts/restartsrv cpanel
secpol="1"
;;
esac
}
function sec-disable() {
case $secpol in
"N") echo "Security Questions is not setup." ;;
"0") echo "Security Questions already disabled." ;;
"1")
echo "Security Questions have been disabled, please ensure you re-enable them before finalizing work."
sed -i 's/SecurityPolicy::SourceIPCheck=1/SecurityPolicy::SourceIPCheck=0/g' /var/cpanel/cpanel.config
/scripts/restartsrv cpanel
secpol="0"
;;
esac
}
#End Security Question Functions
function apache-stats(){
curl -s 'http://localhost/whm-server-status' | perl -ne 'print "$1\n" if m~<td nowrap>(.*?)</td>.*</td></tr>~ ' | sort | uniq -c | sort -n
}
function phpusers(){
grep php /etc/userdatadomains | awk -F'==' '{print $4 " " $10}' | sort | uniq
defaultphp="$(/usr/local/cpanel/bin/rebuild_phpconf --current|sed 's/^/ /' | sed -n 1p | awk -F':' '{print $2}')"
echo "$(grep inherit /etc/userdatadomains | awk -F'==' '{print $4 " " $10}' | sort | uniq | sed -e "s/inherit/inherit ${defaultphp}/g")"
}
function errors() {
D=$(date +%d)
M=$(date +%b)
Y=$(date +%Y)
find . -name error_log | xargs grep $D-$M-$Y
}
#Supplemental Functions for getea4php
function phpeol() {
PHPVer=$1
PHPVer=$(case $PHPVer in
"5.2") echo "2011-06-01" ;;
"5.3") echo "2014-08-14" ;;
"5.4") echo "2015-09-03" ;;
"5.5") echo "2016-07-10" ;;
"5.6") echo "2018-12-31" ;;
"7.0") echo "2018-12-03" ;;
"7.1") echo "2019-12-01" ;;
"7.2") echo "2020-11-30" ;;
"7.3") echo "2021-12-06" ;;
"7.4") echo "2022-11-28" ;;
"8.0") echo "2023-11-26" ;;
"8.1") echo "2024-11-25" ;;
*) echo $PHPVer ;;
esac)
echo $PHPVer
}
function datecheck() {
CDate=$1
D=$(date +%d)
M=$(date +%m)
Y=$(date +%Y)
TDate="$Y-$M-$D"
if [[ "$CDate" > "$TDate" ]]; then
GREEN='\033[0;32m'
NC='\033[0m'
echo -e "${GREEN}${CDate}${NC}"
else
RED='\033[0;31m'
NC='\033[0m'
echo -e "${RED}${CDate}${NC}"
fi
}
#End Supplemental Functions
function getea4php() {
phpcount=$(/usr/local/cpanel/bin/rebuild_phpconf --current|sed 's/^/ /' | wc -l)
for (( c=1; c<=$phpcount; c++))
do
if [[ $c == 1 ]]; then
/usr/local/cpanel/bin/rebuild_phpconf --current|sed 's/^/ /' | sed -n 1p
else
vstr=$(/usr/local/cpanel/bin/rebuild_phpconf --current|sed 's/^/ /' | sed -n $c"p")
vver=$(/usr/local/cpanel/bin/rebuild_phpconf --current|sed 's/^/ /' | awk -F'ea-php' '{print $2}' | awk '{print $1}' | sed -n $c"p")
v1=${vver:0:1}
v2=${vver:1:1}
vc="$v1.$v2"
veol=$(phpeol $vc)
chkeol=$(datecheck $veol)
echo -e ' \t '$vstr $chkeol
fi
done
}
function chksvc() {
case $OS in
[7-8])
httpd="$(service httpd status 2>&1 | awk '$1=="Active:"{print $2}')"
if [[ $httpd = *"inactive" ]]; then
bad "Apache (httpd) is down."
else
UPTIME=$(systemctl status httpd.service | grep Active | awk -F';' '{print $2}')
good "Apache (httpd) is up since$UPTIME"
fi
mysqld="$(service mysqld status 2>&1 | awk '$1=="Active:"{print $2}')"
if [[ $mysqld = *"inactive" ]]; then
bad "MySQL (mysqld) is down."
else
UPTIME=$(systemctl status mysqld.service | grep Active | awk -F';' '{print $2}')
good "MySQL (mysqld) is up since$UPTIME"
fi
DNS=$(grep local_nameserver_type /var/cpanel/cpanel.config | awk -F'=' '{print $2}')
case $DNS in
'bind')
named="$(service named status 2>&1 | awk '$1=="Active:"{print $2}')"
if [[ $named = *"inactive" ]]; then
bad "NAMED (named) is down."
else
UPTIME=$(systemctl status named.service | grep Active | awk -F';' '{print $2}')
good "NAMED (named) is up since$UPTIME"
fi
;;
'powerdns')
powerdns="$(service pdns status 2>&1 | awk '$1=="Active:"{print $2}')"
if [[ $powerdns = *"inactive" ]]; then
bad "POWERDNS (pdns) is down."
else
UPTIME=$(systemctl status pdns.service | grep Active | awk -F';' '{print $2}')
good "POWERDNS (pdns) is up since$UPTIME"
fi
;;
esac
;;
'6')
if [[ -n $(ps aux | grep mysql | grep -v grep) ]] ; then good "MySQL is UP!"; else bad "MySQL is DOWN!"; fi
if [[ -n $(ps aux | grep httpd | grep -v grep) ]] ; then good "Apache is UP!"; else bad "Apache is DOWN!"; fi
if [[ -n $(ps aux | grep named | grep -v grep) ]] ; then good "NAMED is UP!"; else bad "NAMED is DOWN!"; fi
;;
esac
}
#Begin Summary Output
#Script Version Data
SOUT "GreenGeeks MVM System Status Version: $version" "Container: $vzCTID"
#Check Operating System
case $OS in
'5') SOUT "Operating System" "$(bad "$(cat /etc/redhat-release)")" ;;
'6') SOUT "Operating System" "$(bad "$(cat /etc/redhat-release)")" ;;
[7-8]) SOUT "Operating System" "$(good "$(cat /etc/redhat-release)")" ;;
esac
#Check Hostname for formatting, DNS, etc.
if [[ `${HOSTNAMEBIN}|grep -c '.'` -lt 1 ]];then
hname="$B ${HOSTNAME} Invalid Hostname $CLEAR"
else
htest="$(dig +noall +answer ${HOSTNAME} @8.8.8.8)"
if [[ ! -n $htest ]];then
hname="$B ${HOSTNAME} DNS Not Setup $CLEAR"
fi
fi
if [[ -z $hname ]];then
hname="$G ${HOSTNAME} $CLEAR"
fi
SOUT "Hostname" "$hname"
#get Primary IP address
SOUT "Primary IP" $(hostname -i)
#cPanel Version Check
CPVER="$(cat /usr/local/cpanel/version)"
CPV="$(awk -F . '{print $2}' /usr/local/cpanel/version)"
case $CPV in
[4-6][0-9]) SOUT "cPanel Version" "$(bad2 $CPVER)" ;;
7[0-3]) SOUT "cPanel Version" "$(bad2 $CPVER)" ;;
7[4-9]) SOUT "cPanel Version" "$(bad $CPVER)" ;;
[8-9][0-9]) SOUT "cPanel Version" "$(good $CPVER)" ;;
esac
#EasyApache Version Check
cpeaver=`/usr/local/apache/bin/httpd -v|grep Easy|awk '{print $2}'|sed 's/v//'|awk -F. '{print $1}'`
if [[ ${cpeaver} -ne 3 ]]; then
cpeaver=4
fi
case ${cpeaver} in
4)
SOUT "EasyApache" "$(good 'Version 4')"
getea4php
;;
3)
SOUT "EasyApache" "$(bad 'Version 3')"
EA3PHP=$(php -v | head -n 1 | awk '{print $2}' | awk -F'.' '{print $1"."$2}')
EA3PHPEOL=$(phpeol $EA3PHP)
echo -e 'PHP '$EA3PHP $(datecheck $EA3PHPEOL)
;;
esac
#Database Version Check
DB="$(mysql --version | awk '{print $1 " " $5}'| sed 's/.$//')"
DBV="$(echo $DB | awk '{print $2}' | awk -F'.' '{print $1"."$2}')"
case $DBV in
#mysql checks
'5.'[0-5]) SOUT "Database" "$(bad "$DB")" ;;
'5.'[6-7]) SOUT "Database" "$(good "$DB")" ;;
'8.'[0-9]) SOUT "Database" "$(good "$DB")" ;;
#mariadb checks
'10.'[0-2]) SOUT "Database" "$(bad "$DB")" ;;
'10.'[3-9]) SOUT "Database" "$(good "$DB")" ;
esac
#Check Backup Status
backup=$(grep BACKUPENABLE /var/cpanel/backups/config | awk -F"BACKUPENABLE: " '{print $2}' | tr -d \'\")
if [ "$backup" = "no" ];then
SOUT "Backups" "$B Backups are not enabled. $CLEAR"
else
SOUT "Backups" "$G Backups are enabled. $CLEAR"
fi
#Get Server Stats
SOUT "Service Status" "$(chksvc)"
#disk percentage check
DU=`df -h | head -n 2 | tail -n 1 | awk {'print $5'}`
DT=`df -h | head -n 2 | tail -n 1 | awk {'print $2'}`
case $DU in
[0-9]'%') DISK="$(good2 "$DU of $DT")" ;;
[0-4][0-9]'%') DISK="$(good2 "$DU of $DT")" ;;
[5-6][0-9]'%') DISK="$(good "$DU of $DT")" ;;
[7-8][0-9]'%') DISK="$(bad "$DU of $DT")" ;;
[9][0-9]'%') DISK="$(bad2 "$DU of $DT")" ;;
100'%') DISK="$(bad2 "$DU of $DT")" ;;
esac
#memory percentage check
case $OS in
'6')
getmem=`vmstat -s | egrep -v '(swap|cpu|pages|boot|forks|interrupt|switches)'`
gt=$(echo $getmem | awk '{print $1 / 1024}')
gts="$(echo "${gt}MB")"
ga=$(echo $getmem | awk '{print $7 / 1024}' | awk -F'.' '{print $1}')
mp=$((100*$ga/$gt))
;;
[7-8])
getmem=`vmstat -s | egrep -v '(swap|cpu|pages|boot|forks|interrupt|switches)'`
gt=$(echo $getmem | awk '{print $1 / 1024}')
gts="$(echo "${gt}MB")"
ga=$(echo $getmem | awk '{print $9 / 1024}' | awk -F'.' '{print $1}')
mp=$((100*$ga/$gt))
;;
esac
case $mp in
[0-9]) MEMORY="$(good2 "$mp% of $gts")" ;;
[0-4][0-9]) MEMORY="$(good2 "$mp% of $gts")" ;;
[5-6][0-9]) MEMORY="$(good "$mp% of $gts")" ;;
[7-8][0-9]) MEMORY="$(bad "$mp% of $gts")" ;;
[9][0-9]) MEMORY="$(bad2 "$mp% of $gts")" ;;
100) MEMORY="$(bad2 "$mp% of $gts")" ;;
esac
#CPU check
load="$(uptime | awk -F'average:' '{print $2}' | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//')"
SOUT "Server Health" "Disk Usage\t\tMemory\t\t\tLoad"
tload="$(echo $load | awk -F'.' '{print $1}')"
case $tload in
[0-1]) DLOAD="$(good2 "$load")" ;;
[2-3]) DLOAD="$(bad "$load")" ;;
[4-9]) DLOAD="$(bad2 "$load")" ;;
[1-9][0-9]) DLOAD="$(bad2 "$load")" ;;
esac
echo -e "$DISK\t\t$MEMORY\t\t$DLOAD"
#exim check
queueFAIL=100
mailQUEUE=`exim -bpc`
if [[ $mailQUEUE -gt $queueFAIL ]]; then
SOUT "Exim Check" "$(bad2 "Messages in queue: $mailQUEUE")"
else
SOUT "Exim Check" "$(good "Messages in queue: $mailQUEUE")"
fi
unset mailQUEUE
securitycheck="$(grep SecurityPolicy::SourceIPCheck /var/cpanel/cpanel.config)"
if [[ ! -n $securitycheck ]]; then
SOUT "Security Check" "$(bad "Not Found")"
secpol="N"
else
case $securitycheck in
"SecurityPolicy::SourceIPCheck=0") SOUT "Security Check" "$(bad "Disabled")"; secpol="0" ;;
"SecurityPolicy::SourceIPCheck=1") SOUT "Security Check" "$(good "Enabled")"; secpol="1" ;;
esac
fi