Skip to content

Instantly share code, notes, and snippets.

@mnathani
Created May 26, 2023 04:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mnathani/6d58dda14bc966c6d872633a7ed2f47b to your computer and use it in GitHub Desktop.
Save mnathani/6d58dda14bc966c6d872633a7ed2f47b to your computer and use it in GitHub Desktop.
#!/bin/bash
# _ _ _
#__ _| |__ ___ __| | __ _| |_
#\ \ /\ / / '_ \ / _ \ / _` |/ _` | __|
# \ V V /| | | | (_) | (_| | (_| | |_
# \_/\_/ |_| |_|\___/ \__,_|\__,_|\__|
#
#Written by: Mrjung with contributions by mshooltz
#For those who need account information, and need it NOW!
#This is intended to replace use of /scripts/whoowns so techs can get -ALL- the information they
#need right off the bat to work on an issue.
bold=$(tput bold)
normal=$(tput sgr0)
main() {
#check the environment to see which panel we're working with
if [[ -d /usr/local/cpanel ]]; then
run_cpanel $@
return $?
fi
if [[ -d /usr/local/interworx ]]; then
run_iwx $@
return $?
fi
if [[ -d /usr/local/psa ]]; then
run_plesk $@
return $?
fi
} # End main
run_cpanel () {
#Output the usage of how to use this if needed
usage () {
printf "Usage: whodat [Flags] [Domain/User]\n"
printf "Flags:\n\t-h, --help\tShow this help message.\n"
printf "\t-m, --mail\tInclude outbound mailing info in the output.\n"
printf "\t-l, --logs\tInclude the location of some of the relevant logs in the output.\n"
printf "\t-v, --verbose\tShows verbose information about the domain or user.\n\n"
}
cl_lve_check() {
#If Cloudlinux, check for LVE faults that will indicate "resource limits exceeded" errors, or slowness from cpu/IO bottlenecks
if [[ "$cl" == "1" ]] && [[ -n "$(which lveinfo 2>/dev/null)" ]]; then
lvelimits="$(lveinfo --by-fault=any --display-username --period=12h --show-columns ID,CPUf,VMemF,PMemF,EPf,NprocF,IOf,IOPSf)"
if [[ -n "$(echo "$lvelimits" |egrep "^\|$cpuser(\|| )" )" ]]; then
#echo
echo "${bold}CloudLinux LVE limits reached by $cpuser in the last 12 hours:"
echo "$lvelimits" |head -3
echo "$lvelimits" |egrep "^\|$cpuser(\|| )"
echo "$lvelimits${normal}" |tail -1
fi
fi
#Check for user in cageFS:
if [[ $cl == "1" ]]; then
if [[ -e /usr/sbin/cagefsctl ]] && [[ -n "$(cagefsctl --list-enabled |egrep "^$cpuser$" )" ]]; then
printf "User in CageFS:\tYes\n\n"
else
printf "User in CageFS:\tNo\n\n"
fi
fi
} #End cl_lve_check
main_cpanel() {
if [[ -n "$(grep CloudLinux /etc/redhat-release)" ]]; then
cl=1
fi
#Convert any UPPERCASE to lowercase from input.
if [[ -n $(echo $search |egrep '[[:upper:]]') ]]; then
search="$(echo "$search" | tr '[:upper:]' '[:lower:]' )"
fi
#Make sure a domain name has been provided
if [[ -z $search ]]; then
echo ERROR: No domain or username specified!
usage
exit 1
fi
#Make sure a valid search entry has been provided
if [[ -z $search ]]; then
echo Error: No cpanel user or domain specified!
usage
exit 1
fi
#Check if the provided search entry is a user or domain
if [ `id -u $search 2>/dev/null || echo -1` -ge 0 ]; then
fullcpuserlist=`\ls /var/cpanel/users/`
if [[ $fullcpuserlist =~ (^|[[:space:]])"$search"($|[[:space:]]) ]]; then
cpuser="$search"
search_type="user"
list_user_domains
whodat_verbose
cl_lve_check
exit 0
else
echo -e "Error: non-cpanel user specified; please try again with a cpanel user or domain."
exit 1
fi
else
domain="$search"
search_type="domain"
fi
#This is meant for cpanel only. Check if the server is a cpanel server. Exit if not.
if [[ ! -e /usr/local/cpanel ]]; then
echo "cPanel is required to use this script!"
exit 1
fi
#Strip the http protocol from the domain:
if [[ -n $(echo "$domain" |egrep '^https?://') ]]; then
domain="$(echo "$domain" | sed -r 's#^https?://##')"
fi
#Strip www. from the beginning of the domain:
if [[ -n $(echo "$domain" |egrep '^www\.') ]]; then
domain="$(echo "$domain" | sed 's/^www\.//')"
fi
#Remove trailing slash or any URI (if copied from browser, or specific uri supplied)
if [[ -n $(echo "$domain" |egrep '/') ]]; then
domain="$(echo "$domain" | sed -r 's#/.*$##')"
fi
#Check for EA3 or EA4
if [[ -e /etc/cpanel/ea4/is_ea4 ]]; then
ea_ver='4'
apache_conf='/etc/apache2/conf/httpd.conf'
apachectl_command="apachectl -M"
else
ea_ver='3'
apache_conf='/usr/local/apache/conf/httpd.conf'
apachectl_command="httpd -M"
fi
#Assign a variable for the cpanel user, to be called for many things later on
cpuser=$(grep "^$domain:" /etc/userdatadomains |cut -d'=' -f1 |cut -d' ' -f2)
#Get user's homedir
user_homedir="$(readlink -f $(eval echo "~${cpuser}"))"
#Make sure the user exists on the system.
#This vaiable will only be empty at this point if it wasn't found in the above $cpuser variable assignment.
if [[ -z $cpuser ]]; then
#Check for wildcard vhosts that might match the given domain
for vhost in $(grep '*' /etc/userdatadomains |cut -d':' -f1); do
# We need to convert each domain component intro regex to parse wildcards
# Essentially turns "*.domain.com" into
# "([a-z0-9A-Z]|-){1,63}.domain.com" so we can grep it.
get_regex_domain() {
regex_domain=$(echo "$1" | tr '.' '\n' | sed "s/\*/\(\[a\-z0\-9A\-Z\]\|\-\)\{1\,63\}/g" |tr '\n' '.' |rev | cut -d'.' -f2- |rev)
}
#Use the above function to convert the subdomain into regex
get_regex_domain $vhost
if [[ -n "$(echo "$domain" | egrep -s "^$regex_domain" )" ]]; then
is_wildcard_vhost="1"
wildcard_vhost=$vhost
cpuser="$(grep "^$wildcard_vhost" /etc/userdatadomains | awk '{print $2}' | cut -d'=' -f1)"
domain=$wildcard_vhost
wildcard_warning=" ${bold}Wildcard vhost!${normal}"
fi
done
fi
#If we didn't get a match directly from /etc/userdatadomains
#And it didn't match any wildcard vhost, its pretty safe to say cPanel isn't aware of this domain.
if [[ -z $cpuser ]]; then
echo "ERROR: $domain not found in /etc/userdatadomains"
exit 1
fi
echo
#Grab the docroot from /etc/userdatadomains
docroot=$(grep "^$domain:" /etc/userdatadomains |cut -d'=' -f9)
parkedcheck() {
if [[ $domain_type == "parked" ]]; then
parked_on="$(grep ^$domain /etc/userdatadomains | cut -d'=' -f7)"
printf "${bold}Parked on:\t$parked_on${normal}\n"
#Use the Parked destination for the rest of the checks
original_domain=$domain
domain=$parked_on
fi
}
wildcardcheck() {
if [[ $is_wildcard_vhost == "1" ]]; then
#Use the Parked destination for the rest of the checks
original_domain=$search
domain=$wildcard_vhost
fi
}
#Get the IP that WHM has configured for the domain in /etc/userdatadomains
whm_ip=$(grep "^${domain}:" /etc/userdatadomains |cut -d'=' -f11 |cut -d':' -f1)
# Additional check for NAT configuration.
# /etc/userdatadomains will only list the private IP with a NAT setup.
if [[ -e /var/cpanel/cpnat ]]; then
priv_ip=$whm_ip
whm_ip="$(whmapi1 get_public_ip ip=${priv_ip} |grep 'public_ip:' |awk '{print $2}')"
fi
#resolve the A record
a_record=$(dig +short $domain @8.8.8.8 | egrep '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$')
if [[ -z $a_record ]] ; then
a_record="${bold}MISSING!${normal}"
fi
#Check for a AAAA DNS record. With some regex that is way more complicated than I'd like. Source: https://stackoverflow.com/a/17871737
AAAA_record=$(dig +short AAAA $domain @8.8.8.8| egrep '(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))')
#Get the type of domain from /etc/userdatadomains. Main, sub, addon, alias.
domain_type=$(grep ^$domain /etc/userdatadomains |cut -d'=' -f5)
#Output the info
printf "Username:\t$cpuser\n"
printf "${bold}Docroot:\t$docroot\n${normal}"
printf "Domain:\t\t$domain ($domain_type domain)$wildcard_warning\n"
parkedcheck
wildcardcheck
printf "Configured IP:\t$whm_ip\n"
#If there are more than 1 A record, print each one on a new line
for ip in $a_record ; do
printf "A Record:\t$ip\n"
done
#Only print the ipv6 AAAA records if they exist
#And print one on each line if there are more than 1
if [[ -n $AAAA_record ]];then
for ipv6 in $AAAA_record ; do
printf "AAAA Record:\t$ipv6\n"
done
fi
#For EA4
if [[ "$ea_ver" == "4" ]]; then
php_ver=$(grep "^$domain:" /etc/userdatadomains |cut -d'=' -f19)
#If using inherit, the above will not properly determine the version, and the php_ver var will be empty or will be "inherit". If thats the case, just use the default to grab the inherited version:
if [[ -z $php_ver ]] || [[ $php_ver == "inherit" ]] ; then
php_ver=$(/usr/local/cpanel/bin/rebuild_phpconf --current |grep DEFAULT | awk '{print $NF}')
#But its not that simple! It could be inheriting the PHP version from a docroot above it (if there is one)!
#Best I can tell, the simplest way to check for this is to cd to the docroot and let cpanel scl figure out what version of PHP it uses
#Also need to keep in mind that FPM isnt in play, since FPM cant be enabled on domains that inherit their PHP version
cd $docroot
#Have PHP echo out its binary location, and grab the ea-version from the full path
php_bin=$(php -r 'echo PHP_BINARY;' 2>/dev/null |cut -d '/' -f4)
#go back to our previous directory
cd $OLDPWD
if [[ ! "$php_ver" == "$php_bin" ]] ; then
php_ver="$php_bin"
fi
#Need to account for Cloudlinux and PHP selector here.
if [[ $cl == "1" ]] && \
[[ -d /opt/alt ]] && \
[[ -n "$(cagefsctl --list-enabled |egrep "^$cpuser$" )" ]] && \
[[ -z "$(selectorctl -c -u $cpuser | egrep -i '^native')" ]] ; then
php_ver="alt-php$(selectorctl -c -u $cpuser |awk '{print $1}' | tr -d '.' 2>/dev/null)"
using_php_selector_notice="${bold} !!Via CloudLinux PHP Selector!!${normal}"
fi
fi
fi
#And for EA3
if [[ "$ea_ver" == "3" ]]; then
php_ver=$(php -v |head -1 |awk '{print $2}' 2> /dev/null)
fi
#Grabs the FPM status for the domain from whmapi1:
#https://documentation.cpanel.net/display/DD/WHM+API+1+Functions+-+php_get_vhost_versions
#Do this only if EA4
if [[ "$ea_ver" == "4" ]]; then
fpm_status=$(whmapi1 php_get_vhost_versions | egrep '(vhost:|php_fpm:)' |grep -B1 "vhost: $domain$" | grep php_fpm |sed 's/php_fpm: 1/Enabled/' |sed 's/php_fpm: 0/Disabled/' |tr -d " ")
#If we're working with a wildcard vhost, we have to change the grep a little bit
if [[ $is_wildcard_vhost == "1" ]]; then
wildcard_escaped_domain="$(echo "$domain" | sed -r 's/(.*)/\\"\1\\"/g')"
fpm_status=$(whmapi1 php_get_vhost_versions | egrep '(vhost:|php_fpm:)' |grep -B1 "$wildcard_escaped_domain$" | grep php_fpm |sed 's/php_fpm: 1/Enabled/' |sed 's/php_fpm: 0/Disabled/' |tr -d " ")
fi
fi
#Determine the handler:
php_handler=$(/usr/local/cpanel/bin/rebuild_phpconf --current |grep "$php_ver" |awk '{print $NF}' |tail -1)
#If EA3, $php_handler will be empty at this point, since we get the full version from php -v. Grab the handler from /usr/local/cpanel/bin/rebuild_phpconf --current
if [[ "$ea_ver" == '3' ]]; then
php_handler=$(/usr/local/cpanel/bin/rebuild_phpconf --current |grep 'PHP5 SAPI' |awk '{print $NF}')
fi
printf "PHP Version:\t$php_ver$using_php_selector_notice\n"
#We'll create if/elif statements for each possible handler, and account for suexec/ruid where applicable.
if [[ "$fpm_status" == "Enabled" ]] ;then
printf "PHP Handler:\tPHP-FPM $fpm_status\n"
elif [[ "$php_handler" == "dso" ]]; then
#determine if mod_ruid is in place
if [[ -n "$($apachectl_command 2>&1 |grep ruid)" ]]; then
ruid_status="With Mod_RUID (PHP runs as user)"
else
ruid_status="Without Mod_RUID (PHP runs as nobody, NOT the user)"
fi
if [[ $ea_ver == '3' ]]; then
ruid_status="$(/usr/local/cpanel/bin/rebuild_phpconf --current |grep RUID2)"
fi
printf "PHP Handler:\tDSO $ruid_status\n"
elif [[ "$php_handler" == "suphp" ]]; then
printf "PHP Handler:\tSuPHP\n"
elif [[ "$php_handler" == "cgi" ]]; then
#determine if SuExec is in place
if [[ -n $($apachectl_command 2>&1 |grep suexec) ]]; then
suexec_status="- With SuExec"
else
suexec_status="- WITHOUT SuExec"
fi
if [[ $ea_ver == '3' ]]; then
suexec_status="$(/usr/local/cpanel/bin/rebuild_phpconf --current |grep SUEXEC)"
fi
printf "PHP Handler:\tCGI $suexec_status\n"
elif [[ "$php_handler" == "fcgi" ]]; then
#determine if SuExec is in place
if [[ -n $($apachectl_command 2>&1 |grep suexec) ]]; then
suexec_status="- With SuExec"
else
suexec_status="- WITHOUT SuExec"
fi
if [[ $ea_ver == '3' ]]; then
suexec_status="$(/usr/local/cpanel/bin/rebuild_phpconf --current |grep SUEXEC)"
fi
printf "PHP Handler:\tFast CGI $suexec_status\n"
elif [[ "$php_handler" == "none" ]]; then
printf "PHP Handler:\tNONE - Is this intended?\n"
#And a final else statement to capture any other handler like lsapi, or anything else cpanel might add:
else
printf "PHP Handler:\t$php_handler\n"
fi
#Check for Common CMS signatures.
#Each of these checks basically make sure there is no index.html (which historically had a higher priority index file than index.php)
#And checks for common strings of code that would identify a particular CMS
checkif_wordpress() {
#Wordpress
if [[ ! -f "$docroot/index.html" ]] && [[ -f "$docroot/index.php" ]] && [[ -n "$(grep -s 'Front to the WordPress application' $docroot/index.php)" ]]; then
cms='WordPress'
#Get the wp version if we can
version="$(grep -s '^\$wp_version' "$docroot/wp-includes/version.php" |cut -d\' -f2)"
#Check the security status of the installed wp version. This will mention if the wordprress version is up-to-date, outdated, or insecure.
if [[ -n "$version" ]]; then
version_status="$(curl -s http://api.wordpress.org/core/stable-check/1.0/ |grep "\"$version\"" |head -1 |cut -d'"' -f4)"
fi
if [[ -n $version_status ]]; then
printable_version_status=" ($version_status)"
fi
return 63
#Exit the loop and don't check for other CMS's if we've identified one
#Previously used `break` - but that was apparently a bug since its called within a function https://github.com/samuelcolvin/bash/blob/a0c0a00fc419b7bc08202a79134fcd5bc0427071/CHANGES#L677
fi
}
checkif_joomla() {
#Joomla3.x
if [[ ! -f "$docroot/index.html" ]] && [[ -n "$(grep -s 'Joomla.Site' $docroot/index.php)" ]];then
cms='Joomla'
if [[ -f "$docroot/libraries/src/Version.php" ]]; then
minor_version=".$(grep 'const MINOR_VERSION' $docroot/libraries/src/Version.php |egrep -o '[0-9]{1,2}')"
patch_version=".$(grep 'const PATCH_VERSION' $docroot/libraries/src/Version.php |egrep -o '[0-9]{1,2}')"
version="3$minor_version$patch_version"
elif [[ ! -f "$docroot/index.html" ]] && [[ -n "$(grep -s 'Joomla.Site' $docroot/index.php)" ]] && [[ -n "$(grep -s 'public $RELEASE =' "$docroot/libraries/cms/version/version.php" |grep 2)" ]]; then
minor_version=".$(grep -s 'public $DEV_LEVEL =' "$docroot"/libraries/cms/version/version.php | egrep -o '[0-9]{1,2}')"
version="2.5$minor_version"
else
version=''
fi
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_drupal() {
if [[ ! -f "$docroot/index.html" ]] && [[ -n "$(grep -s 'The PHP page that serves all page requests on a Drupal installation' $docroot/index.php)" ]];then
cms='Drupal'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_magento() {
#Magento
if [[ ! -f "$docroot/index.html" ]] && [[ -n "$(egrep -si "Copyright.*Magento, Inc" $docroot/index.php)" ]];then
cms='Magento'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_whmcs() {
#WHMCS
if [[ ! -f "$docroot/index.html" ]] && [[ -n "$(egrep -si "WHMCS - The Complete Client Management, Billing & Support Solution" $docroot/index.php)" ]];then
cms='WHMCS'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_prestashop() {
#Prestashop
if [[ ! -f "$docroot/index.html" ]] && [[ -n "$(egrep -si '@author[[:blank:]]*PrestaShop SA' $docroot/index.php)" ]];then
cms='PrestaShop'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_phpbb() {
#PHPBB
if [[ ! -f "$docroot/index.html" ]] && [[ -n "$(egrep -si "PHPBB_ROOT_PATH" $docroot/index.php)" ]];then
cms='phpBB'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
for cms_check in checkif_wordpress checkif_joomla checkif_drupal checkif_magento checkif_whmcs checkif_prestashop checkif_phpbb
do $cms_check
done
if [[ -z "$cms" ]]; then
cms='unknown'
fi
#Only print CMS if defined Version is empty unless found by the wordpress or joomla check
if [[ ! "$cms" == 'unknown' ]]; then
printf "CMS:\t\t$cms $version${printable_version_status}\n"
fi
#Check for userdata Apache includes for the domain.
#Need to check the subdomain for the include of an addon domain
if [[ $domain_type == "addon" ]]; then
include_domain=$(grep ^$domain /etc/userdatadomains |cut -d'=' -f7)
else
include_domain=$domain
fi
if [[ "$is_wildcard_vhost" == "1" ]]; then
include_domain=$(echo "$wildcard_vhost" | sed 's/*/wildcard_safe/g')
fi
#active_includes="$(grep "/$include_domain/" $apache_conf | grep Include | grep -v '#' | cut -d'"' -f2)"
active_includes="$(egrep "/$cpuser/$include_domain/|/$cpuser/\*\.conf" $apache_conf | grep Include | grep -v '#' | cut -d'"' -f2 |sort | uniq)"
if [[ -n "$active_includes" ]]; then
echo
#If multiple include files exist, print each one out on its own line
old_ifs=$IFS
IFS='
'
for include in $(find $active_includes -name "*.conf" -maxdepth 0 2>/dev/null); do
printf "VHOST INCLUDE:\t$include"
if [[ -h "$include" ]]; then
#Add a note stating that its a symlink
printf " (${bold}Symlink${normal})\n"
else
printf "\n"
fi
done
IFS=$old_ifs
fi
#Warn if user has exceed disk quota:
if [[ -n "$(quota -uq $cpuser 2>/dev/null | grep "Block limit reached")" ]]; then
printf "\n[WARNING]\tCpanel user: $cpuser has reached Disk Quota!\n"
fi
#Warn only if account is suspended
if [[ -e /var/cpanel/suspendinfo/$cpuser ]]; then
printf "\n[WARNING]\tACCOUNT IS SUSPENDED\n"
fi
#Warn if we do a non-standard suspension
if [[ -n "$(grep -s 'suspendedpage.cgi' ${user_homedir}/.htaccess)" ]]; then
printf "\n[WARNING]\tThe account appears suspended via redirect in ${user_homedir}/.htaccess\n"
#Extra check to let the user know if it is immutable.
if [[ -n "$(lsattr ${user_homedir}/.htaccess |awk '{print $1}' |grep 'i')" ]]; then
printf "\t\t \_You must 'chattr -i' the .htaccess file before you can edit it!\n\t\t Check the recent tickets on the account to see why it was suspended.\n\t\t Any security issues must be corrected before (or immediately after) we unsuspend."
fi
fi
echo
} #End main
whodat_check_mail() {
if [[ "$mail_was_run" == '1' ]]; then
echo
echo "HEY!"
sleep 1
echo "LISTEN!"
sleep 1
echo "You don't have to use -m with -v!"
sleep 1
echo "-v already shows mail info!"
sleep 3
return
fi
if [[ "$run_mail" == '1' ]] && [[ "$search_type" == "domain" ]]; then
rdns_lookup() {
if [[ "$cpanel_version" -ge '78' ]]; then
#https://documentation.cpanel.net/display/DD/WHM+API+1+Functions+-+validate_current_ptrs
full_rdns_api_output="$(whmapi1 validate_current_ptrs domain=$domain)"
rdns_status="$(echo "$full_rdns_api_output" |egrep '^ state:' |awk '{print $2}')"
ptr_record="$(echo "$full_rdns_api_output" |grep -A2 ' ptr_records:' |tail -1 |awk '{print $2}')"
if [[ "$rdns_status" == "VALID" ]]; then
rdns_message="Reverse DNS:\t [Success] Sending mail IP: $sendingip has a PTR record: $ptr_record which resolves back to $sendingip.\n"
elif [[ "$rdns_status" == "HELO_MISMATCH" ]] || [[ "$rdns_status" == "PTR_MISMATCH" ]]; then
#HELO_MISMATCH: As of March 3, 2019, cpanel's documentation doens't cover exactly what this error means. It appears that it means the PTR recrd exists, but doesnt resolve back to the sending mail IP
#They do define PTR_MISMATCH to be a similar thing, so lumpung that in with this.
rdns_message="Reverse DNS:\t [FAIL] The RDNS for the sending mail IP: $sendingip has a PTR record: $ptr_record, but the PTR record DOES NOT resolve back as an A RECORD to $sendingip.\n"
elif [[ "$rdns_status" == "MISSING_PTR" ]]; then
rdns_message="Reverse DNS:\t [FAIL] Missing PTR record for $sendingip.\n"
else
rdns_message="Reverse DNS:\t [FAIL] Unknown error, check rdns manually.\n"
fi
printf "$rdns_message"
fi
} #end rdns_lookup
#Get the cpanel version. The api calls required to validate dkim and spf are only available in that version or newer
cpanel_version="$(cut -d '.' -f2 /usr/local/cpanel/version)"
dkim_validation() {
dkim_record="$(dig +short default._domainkey.$domain TXT)"
if [[ "$cpanel_version" -ge '78' ]]; then
#This API call should return two STATE= lines. they should both return 'VALID' for it to be good.
dkim_status="$(whmapi1 validate_current_dkims domain=$domain |grep 'state:' |sed 's/^[[:blank:]]*//g' |uniq)"
if [[ "$dkim_status" == 'state: VALID' ]]; then
printf "DKIM Record:\t [Success] Valid DKIM record found on default._domainkey.$domain\n"
elif [[ -z "$dkim_record" ]]; then
printf "DKIM Record:\t [MISSING] No dkim record found on default._domainkey.$domain \n"
else
printf "DKIM Record:\t [Fail] The dkim on default._domainkey.$domain is not valid \n"
fi
#Print notice if there are multiple dkim records
if [[ $(echo "$dkim_record" |wc -l) -ge 2 ]]; then
printf "DKIM Record:\t [Notice] - More than 1 DKIM record was returned on default._domainkey.$domain. - Is this intentional?\n"
fi
fi
} # end dkim_validation
spf_validation() {
if [[ "$cpanel_version" -ge '78' ]]; then
spf_record="$(dig txt $domain +short |grep -i 'v=spf')"
#grab the spf status from the WHM api:
spf_status="$(whmapi1 validate_current_spfs domain=$domain |egrep -o 'state: (VALID|MISMATCHED|MULTIPLE|MISSING|INVALID)' |awk '{print $2}')"
if [[ "$spf_status" == 'VALID' ]]; then
printf "SPF Record:\t [Success] The SPF record on $domain authorizes $sendingip to send mail.\n"
elif [[ "$spf_status" == 'MISMATCHED' ]] || [[ "$spf_status" == 'INVALID' ]]; then
printf "SPF Record:\t [Fail] The SPF record on $domain exists, but does NOT authorize $sendingip to send mail.\n"
elif [[ "$spf_status" == 'MULTIPLE' ]]; then
printf "SPF Record:\t [Notice] There are multiple SPF records on $domain. This is NOT recommended, and goes against https://tools.ietf.org/html/rfc7208#section-3 \n"
elif [[ "$spf_status" == 'MISSING' ]]; then
printf "SPF Record:\t [Fail] No SPF record was found on $domain.\n"
fi
fi
} # End spf_validation
echo 'Mail Information:======================================================='
echo
if [[ $domain_type == "parked" ]]; then
#Switch back to the parked domain for dns checks
domain=$original_domain
fi
#Get the IP that WHM has configured for the domain in /etc/userdatadomains
MX_record=$(dig +noall +answer +additional mx $domain |egrep -v '^\;|^$')
if [[ -z "$MX_record" ]]; then
printf "MX Record:\t ${bold}NONE!${normal} "
else
echo "$MX_record"
fi
echo
if [[ -n $(egrep "^$domain$" /etc/localdomains) ]]; then
mailexchanger='LOCAL'
fi
if [[ -n $(egrep "^$domain$" /etc/remotedomains) ]]; then
mailexchanger='REMOTE'
fi
if [[ -n $(egrep "^$domain$" /etc/secondarymx) ]]; then
mailexchanger="BACKUP <---Is this intended?"
fi
printf "Mail Exchange:\t $mailexchanger\n"
primary_ip="$(cat /var/cpanel/mainip)"
#Set variables for the settings that can affect which IP mail get sent from
get_ip_from_mailips() {
sendingip="$(grep "^$domain:" /etc/mailips |awk '{print $2}')"
#If sendingip is empty, grep the *: line:
if [[ -z "$sendingip" ]]; then
sendingip="$(grep '^*:' /etc/mailips |awk '{print $2}')"
fi
}
#Check for use of /etc/mailips:
if [[ "$(grep custom_mailips /etc/exim.conf.localopts |cut -d '=' -f2)" == "1" ]]; then
#This applies if "Reference /etc/mailips for custom IP on outgoing SMTP connections" is enabled.
get_ip_from_mailips
elif [[ "$(grep per_domain_mailips /etc/exim.conf.localopts |cut -d '=' -f2)" == "1" ]]; then
#This applies if mail is configured to send from the account's dedicated IP
sendingip=$whm_ip
else
#This should catch the default behavior of sending form the server's primary IP, where WHM > Exim config > domain's an IP's has all 3 options turned off
sendingip="$primary_ip"
fi
printf "Mail Sends From: $sendingip\n\n"
rdns_lookup
dkim_validation
spf_validation
if [[ "$cpanel_version" -lt '78' ]]; then
printf "Unable to automatically check the RDNS, SPF and DKIM. The API calls needed are only available on cPanel version 78 and newer."
fi
#Added a var to detect that mail was already run. Used to catch instances where -m and -v were used at the same time.
mail_was_run=1
fi
} #end whodat_check_mail
whodat_verbose() {
#Add some verbose stuff. Everything from this point on only shows if --verbose or -v is called
if [[ "$run_verbose" = '1' ]]; then
search=$cpuser
if [[ "$search_type" == "domain" ]]; then
echo "Domains and docroots for $cpuser:=======================================================" |head -c 72
printf "\n\n"
list_user_domains
fi
run_mail=1
whodat_check_mail
echo 'Account Settings:======================================================='
#Grab a bunch of stuff from an API call that we can use later
apiinfo="$(whmapi1 accountsummary user=$cpuser | sed 's/^ //g' | egrep '^(backup:|legacy_backup|disklimit:|diskused|inodeslimit:|inodesused:|plan:|startdate|theme:|shell:)' | sed -e 's/:\ 0$/: Disabled/g' |sed -e 's/:\ 1$/: Enabled/g')"
echo
echo "$apiinfo"
echo
echo 'Crontab:================================================================'
echo
#Display user's crons
crontab -u $cpuser -l
echo
fi
} #end whodat_verbose
#function for lookup by cpanel user to get domain list
list_user_domains () {
if [[ ! -e /usr/local/cpanel/bin/whmapi1 || ! -e /usr/local/cpanel/bin/cpapi2 ]]; then
echo '[ERROR] whmapi and cpapi are required for this! Exiting.'
exit 1
fi
echo "Main Domain: $(egrep ": $search==([a-z_][a-z0-9_]{0,30})==main" /etc/userdatadomains | cut -d ':' -f1)" |awk '{print $1,$2"\t"$3}'
echo "Main Docroot: $(egrep ": $search==([a-z_][a-z0-9_]{0,30})==main" /etc/userdatadomains |cut -d'=' -f9)" |awk '{print $1,$2"\t"$3}'
#Grab subdomains in this cpanel account
subdomains=$(cpapi2 --user=$cpuser SubDomain listsubdomains api2_columns=1 api2_columns_a=domain api2_columns_b=dir |egrep '^ domain:|^ dir:' |sed 's/^ domain: .*$/&\n/g' |sed 's/^ dir:/ Docroot:/g' |sed 's/domain: /Subdomain: /g' |tac |awk '{print $1"\t"$2}')
if [[ -n "$subdomains" ]];then
echo "$subdomains"
fi
#addon domains:
addondomains=$(cpapi2 --user=$cpuser AddonDomain listaddondomains api2_columns=1 api2_columns_a=domain api2_columns_b=dir |egrep '^ domain:|^ dir:' |sed 's/^ domain: .*$/&\n/g' |sed 's/^ dir:/ Docroot:/g' |sed 's/domain: /AddonDomain: /g' |tac |awk '{print $1"\t"$2}')
if [[ -n "$addondomains" ]];then
echo "$addondomains"
fi
parkeddomains="$(cpapi2 --user=$cpuser Park listparkeddomains api2_columns=1 api2_columns_a=domain api2_columns_b=dir |egrep '^ domain:|^ dir:' |sed 's/^ domain: .*$/&\n/g' |sed 's/^ dir:/ Docroot:/g' |sed 's/domain: /ParkedDomain: /g' |tac |awk '{print $1"\t"$2}')"
if [[ -n "$parkeddomains" ]]; then
echo "$parkeddomains"
echo
fi
} #end CPuser_listdomains
cpanel_run_logs() {
if [[ $run_logs = 1 ]] && [[ "$search_type" == "domain" ]]; then
if [[ $domain_type == "addon" ]]; then
#cpanel logs addon domains as their subdomain.
log_domain=$(grep ^$domain /etc/userdatadomains |cut -d'=' -f7)
else
log_domain=$domain
fi
echo 'Logs:==================================================================='
echo
if [[ $ea_ver = 3 ]]; then
printf "Apache Error Log:\t/usr/local/apache/logs/error_log\n"
printf "Today's Apache Domlogs:\t\t/usr/local/apache/domlogs/${cpuser}/${log_domain}\n"
printf "\t\t\t/usr/local/apache/domlogs/${cpuser}/${log_domain}-ssl_log\n"
printf "Archived Domlog Dir:\t${user_homedir}/logs/\n"
fi
if [[ $ea_ver = 4 ]]; then
printf "Apache Error Log:\t/var/log/apache2/error_log\n"
printf "Today's Apache Domlogs:\t/var/log/apache2/domlogs/${cpuser}/${log_domain}\n"
printf "\t\t\t/var/log/apache2/domlogs/${cpuser}/${log_domain}-ssl_log\n"
printf "Archived Domlog Dir:\t${user_homedir}/logs/\n"
if [[ $fpm_status == 'Enabled' ]]; then
printf "PHP-FPM Error Log:\t/opt/cpanel/${php_ver}/root/usr/var/log/php-fpm/error.log\n"
fi
fi
mysql_error_log="$(mysqladmin -s variables | grep log_error |awk '{print $4}')"
if [[ -e $mysql_error_log ]]; then
printf "MySQL Error Log:\t$mysql_error_log\n"
fi
printf "Exim (SMTP) Log:\t/var/log/exim_mainlog\n"
printf "IMAP/POP3 Log:\t\t/var/log/maillog\n"
printf "FTP Log:\t\t/var/log/messages\n"
printf "SSH/SFTP Log: \t\t/var/log/secure\n\n"
fi
} #End cpanel_run_logs
#Handle arguments passed to the script
flags="$(echo " $@" | egrep -o '[[:blank:]]-.*([[:blank:]]|$)')"
#Ensure a valid domain name, username or url was provided
search="$(echo " $@" | egrep -o '[[:blank:]](https?://|)[[:alnum:]]([[:alnum:]]|-|\.|/|\?|\&i|_)*([[:blank:]]|$)' | awk '{print $1}')"
#echo flags: $flags
#echo search: $search
#echo raw args :$@
#check for -m or --mail being called
if [[ -n $(echo "$flags" |egrep -- '[[:blank:]]-[[:alpha:]]?m|[[:blank:]]--mail') ]];then
#echo "Running mail"
run_mail=1
fi
#check for -v or --verbose being called
if [[ -n $(echo "$flags" |egrep -- '[[:blank:]]-[[:alpha:]]?v|[[:blank:]]--verbose') ]];then
#echo "Running verbose"
run_verbose=1
fi
#check for -l or --logs being called
if [[ -n $(echo "$flags" |egrep -- '[[:blank:]]-[[:alpha:]]?l|[[:blank:]]--logs') ]];then
run_logs=1
fi
if [[ -n $(echo "$flags" |egrep -- '[[:blank:]]-[[:alpha:]]?h|[[:blank:]]--help') ]];then
#We'll just print the help message here and exit.
printf "Usage: whodat [Flags] [Domain/User]\n"
printf "Flags:\n\t-h, --help\tShow this help message.\n"
printf "\t-l, --logs\tShow the location of logs relevant to this domain.\n"
printf "\t-m, --mail\tInclude outbound mailing info in the output.\n"
printf "\t-v, --verbose\tShows verbose information about the domain or user.\n\n"
exit 0
fi
#Further sanity checking input prior to main().
#Making sure the user only put a single domain
if [[ -n "$2" ]] && [[ ! "$run_verbose" == "1" ]] && [[ ! "$run_mail" == "1" ]] && [[ ! "$run_logs" == "1" ]]; then
echo '[Error] Only specify one domain at a time'
usage
exit 1
fi
main_cpanel "$search"
whodat_check_mail
cpanel_run_logs
whodat_verbose
cl_lve_check
} # End run_cpanel
#=====================================================================================================================================
#=====================================================================================================================================
#CPANEL ENDS HERE
#=====================================================================================================================================
#=====================================================================================================================================
#=====================================================================================================================================
#Begin Interworx section
run_iwx () {
#Whodat for Interworx
#Make sure a domain name has been provided
#domain=$1
#Handle arguments passed to the script
flags="$(echo " $@" | egrep -o '[[:blank:]]-.*([[:blank:]]|$)')"
#Retrieve the domain name or username from the search. Basically pull any passed arguments that don't start with -
domain="$(echo " $@" | egrep -o '[[:blank:]](https?://|)[[:alnum:]]([[:alnum:]]|-|\.|/|\?|\&|_)*([[:blank:]]|$)' | awk '{print $1}')"
usage () {
printf "Usage: whodat [Flags] [Domain]\n"
printf "Flags:\n\t-h, --help\tShow this help message.\n"
printf "\t-l, --logs\tInclude the location of some of the relevant logs in the output."
printf "\t-v, --verbose\tShows verbose information about the domain or user.\n\n"
}
#echo flags: $flags
#echo search: $search
#echo raw args :$@
#check for -v or --verbose being called
if [[ -n $(echo "$flags" |egrep -- '[[:blank:]]-[[:alpha:]]?v|[[:blank:]]--verbose') ]];then
#echo "Running verbose"
run_verbose=1
fi
#check for -l or --logs being called
if [[ -n $(echo "$flags" |egrep -- '[[:blank:]]-[[:alpha:]]?l|[[:blank:]]--logs') ]];then
#echo "Running verbose"
run_logs=1
fi
if [[ -n $(echo "$flags" |egrep -- '[[:blank:]]-[[:alpha:]]?h|[[:blank:]]--help') ]];then
usage
exit 0
fi
if [[ -z $domain ]]; then
echo ERROR: No domain specified!
usage
exit 1
fi
#Convert any UPPERCASE to lowercase from input.
if [[ -n $(echo $domain |egrep '[[:upper:]]') ]]; then
domain="$(echo "$domain" | tr '[:upper:]' '[:lower:]' )"
fi
#Strip the http protocol from the domain:
if [[ -n $(echo "$domain" |egrep '^https?://') ]]; then
domain="$(echo "$domain" | sed -r 's#^https?://##')"
fi
#Strip www. from the beginning of the domain:
if [[ -n $(echo "$domain" |egrep '^www\.') ]]; then
domain="$(echo "$domain" | sed 's/^www\.//')"
fi
#Remove trailing slash or any URI (if copied from browser, or specific uri supplied)
if [[ -n $(echo "$domain" |egrep '/') ]]; then
domain="$(echo "$domain" | sed -r 's#/.*$##')"
fi
#Check if the provided search entry is a domain on this server
domaincheck="$(nodeworx -u -c siteworx --action queryDomain --domain $domain -n)"
if [[ -z $(echo "$domaincheck" |egrep '^exists: 1$') ]]; then
echo "[Error] $domain does not appear to be a domain on $(hostname). Exiting."
exit 1
else
domaintype="$(echo "$domaincheck" |egrep '^details: ' |awk '{print $2}')"
fi
# We have to do checks differently for each type of domain unfortunately.
if [[ $domaintype == "master" ]]; then
php_raw="$(nodeworx -u -c Siteworx -a queryDomainAccountDetails --domain $domain -o pretty -n |tr -d '"' |tr -d '\\' |sed -r 's/^(\{|\}).*$|^\ \ |,$//g' |egrep '^php_version:' |cut -d ':' -f2)"
if [[ -n $(echo "$php_raw" |grep '/opt/remi') ]]; then
php_ver="$($php_raw/root/bin/php -v 2>/dev/null |head -1 | awk '{print $1,$2}') (Remi)"
php_handler='PHP-FPM' #The remi php versions are only avaialble with FPM
fi
if [[ -n $(echo "$php_raw" |grep 'system-php') ]]; then
php_ver="$(php -v 2>/dev/null |head -1 | awk '{print $1,$2}') (System default)"
#Check which PHP handler the default PHP version uses.
php_handler="$(nodeworx -u -c Http --action listPhpInstallMode |cut -d '_' -f2 |tr "[:lower:]" "[:upper:]")"
fi
user_and_docroot="$(nodeworx -u -c Siteworx -a queryDomainAccountDetails --domain $domain -n --output-style pretty |tr -d '"' |tr -d '\\' |tr -d ',' |sed 's/^[[:blank:]]*//g' |egrep '^uniqname:|^docroot:')"
user="$(echo "$user_and_docroot" |egrep '^uniqname'|cut -d ':' -f2)"
user_homedir="$(readlink -f $(eval echo "~${user}"))"
docroot="$(echo "$user_and_docroot" | egrep '^docroot:' |cut -d ':' -f2)"
configured_ip="$(nodeworx -u -c Siteworx --action querySiteworxAccounts --domain $domain --account_data ip -n)"
pretty_domain_type="Primary "
elif [[ $domaintype == "slave" ]]; then
#Grabs username phpver docroot
domaininfo="$(nodeworx -u -c Siteworx --action listDomainAccounts --output-style pretty |tr -d '"' |tr -d '\\' |tr -d ',' |sed 's/^[[:blank:]]*//g' | sed -n "/^domain:$domain$/,/^docroot:.*/p" |egrep '^php_version:|^docroot:')"
user="$(echo "$domaininfo" |egrep '^docroot' |cut -d ':' -f2 |cut -d '/' -f4)"
user_homedir="$(readlink -f $(eval echo "~${user}"))"
php_raw=$(echo "$domaininfo" |egrep '^php_version:' |cut -d ':' -f2)
docroot=$(echo "$domaininfo" |egrep '^docroot:' |cut -d ":" -f2 )
if [[ -n $(echo "$php_raw" |grep '/opt/remi') ]]; then
php_ver="$($php_raw/root/bin/php -v 2>/dev/null |head -1 | awk '{print $1,$2}') (Remi)"
php_handler='PHP-FPM'
fi
if [[ -n $(echo "$php_raw" |grep 'system-php') ]]; then
php_ver="$(php -v 2>/dev/null |head -1 | awk '{print $1,$2}') (System default)"
php_handler="$(nodeworx -u -c Http --action listPhpInstallMode |cut -d '_' -f2 |tr "[:lower:]" "[:upper:]")"
fi
# As far as I can tell, there isn't an easy way to grab the configured IP from the nodeworx cli, so I'm going to grab it from the vhost
configured_ip="$(grep VirtualHost /etc/httpd/conf.d/vhost_${domain}.conf |grep ':80' |awk '{print $2}' |cut -d':' -f1)"
#Translate the domain type to be "secondary", so it will match the front end label.
pretty_domain_type="Secondary "
elif [[ $domaintype == "subdomain" ]]; then
# Grabs username phpver parent_docroot base_domain
sub_info="$(nodeworx -u -c Siteworx -a queryDomainAccountDetails --domain $domain -n -o pretty |tr -d '"' |tr -d '\\' |tr -d ',' |sed 's/^[[:blank:]]*//g' |egrep '^uniqname:|^php_version:|^docroot:|^domain:')"
user="$(echo "$sub_info" |egrep '^uniqname:' |cut -d ':' -f2)"
user_homedir="$(readlink -f $(eval echo "~${user}"))"
php_ver="$(echo "$sub_info" |egrep '^php_version:' |cut -d ':' -f2)"
parent_docroot="$(echo "$sub_info" |egrep '^docroot:' |cut -d ':' -f2)"
base_domain="$(echo "$sub_info" |egrep '^domain:' |cut -d ':' -f2)"
#So to get the docroot, we need to effectively the provided subdomain, remove the portion of that name that is the base domain, and add whats left to the base docroot
#need to make a variable for the domain with escaped periods to use for the next sed
escaped_base_domain="$(echo "$base_domain" |sed 's/\./\\./g')"
subdomain_part="$(echo "$domain" | sed "s/\.$escaped_base_domain//g")"
docroot="$parent_docroot/$subdomain_part"
if [[ -n $(echo "$php_ver" |grep '/opt/remi') ]]; then
php_ver="$($php_ver/root/bin/php -v 2>/dev/null |head -1 | awk '{print $1,$2}') (Remi)"
php_handler='PHP-FPM'
fi
if [[ -n $(echo "$php_ver" |grep 'system-php') ]]; then
php_ver="$(php -v 2>/dev/null |head -1 | awk '{print $1,$2}') (System default)"
php_handler="$(nodeworx -u -c Http --action listPhpInstallMode |cut -d '_' -f2 |tr "[:lower:]" "[:upper:]")"
fi
#For the configured IP, subdomains are stuck with the same as the main domain, so just grab that
configured_ip=$(nodeworx -u -c Siteworx --action querySiteworxAccounts --domain $base_domain --account_data ip -n)
pretty_domain_type="Sub"
elif [[ $domaintype == "pointer" ]]; then
#nodeworx cli has almost no info on pointer domains, going to have to rely on the vhost for this one
#Grab the conf file we'll be referencing:
pointer_conf="$(egrep -l "ServerAlias.*\ $domain\ " /etc/httpd/conf.d/* |head -1)"
parent_domain=$(grep 'ServerName' $pointer_conf |awk '{print $2}' |head -1)
docroot="$(grep 'DocumentRoot' $pointer_conf |awk '{print $2}' |head -1)"
#Grab the PHP version of the parent domain
php_ver="$(nodeworx -u -c Siteworx -a queryDomainAccountDetails --domain $parent_domain -o pretty -n |tr -d '"' |tr -d '\\' |sed -r 's/^(\{|\}).*$|^\ \ |,$//g' |egrep '^php_version:' |cut -d ':' -f2)"
if [[ -n $(echo "$php_ver" |grep '/opt/remi') ]]; then
php_ver="$($php_ver/root/bin/php -v 2>/dev/null |head -1 | awk '{print $1,$2}') (Remi)"
php_handler='PHP-FPM'
fi
if [[ -n $(echo "$php_ver" |grep 'system-php') ]]; then
php_ver="$(php -v 2>/dev/null |head -1 | awk '{print $1,$2}') (System default)"
php_handler="$(nodeworx -u -c Http --action listPhpInstallMode |cut -d '_' -f2 |tr "[:lower:]" "[:upper:]")"
fi
configured_ip="$(grep VirtualHost $pointer_conf |egrep ':80' |awk '{print $2}' |cut -d':' -f1)"
pretty_domain_type="Pointer "
user=$(nodeworx -u -c Siteworx -a queryDomainAccountDetails --domain $parent_domain -o pretty -n |tr -d '"' |tr -d '\\' |sed -r 's/^(\{|\}).*$|^\ \ |,$//g' |egrep '^uniqname:' |cut -d ':' -f2)
user_homedir="$(readlink -f $(eval echo "~${user}"))"
fi
#resolve the A record
a_record=$(dig +short $domain @8.8.8.8 | egrep '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$')
if [[ -z $a_record ]] ; then
a_record="${bold}MISSING!${normal}"
fi
#Check for a AAAA DNS record. With some regex that is way more complicated than I'd like. Source: https://stackoverflow.com/a/17871737
AAAA_record=$(dig +short AAAA $domain @8.8.8.8| egrep '(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))')
#Print out the information
printf "\nUsername:\t$user\n"
printf "${bold}Docroot:\t$docroot\n${normal}"
printf "Domain:\t\t$domain (${pretty_domain_type}domain)\n"
if [[ $domaintype == 'pointer' ]]; then
printf "Parked on:\t$parent_domain\n"
fi
printf "Configured IP:\t$configured_ip\n"
#If there are more than 1 A record, print each one on a new line
for ip in $a_record ; do
printf "A Record:\t$ip\n"
done
#Only print the ipv6 AAAA records if they exist
#And print one on each line if there are more than 1
if [[ -n $AAAA_record ]];then
for ipv6 in $AAAA_record ; do
printf "AAAA Record:\t$ipv6\n"
done
fi
printf "PHP Version:\t$php_ver\n"
printf "PHP Handler:\t$php_handler\n"
checkif_wordpress() {
#Wordpress
if [[ ! -f "$docroot/index.html" ]] && [[ -f "$docroot/index.php" ]] && [[ -n "$(grep -s 'Front to the WordPress application' $docroot/index.php)" ]]; then
cms='WordPress'
#Get the wp version if we can
version="$(grep -s '^\$wp_version' "$docroot/wp-includes/version.php" |cut -d\' -f2)"
#Check the security status of the installed wp version. This will mention if the wordprress version is up-to-date, outdated, or insecure.
if [[ -n "$version" ]]; then
version_status="$(curl -s http://api.wordpress.org/core/stable-check/1.0/ |grep "\"$version\"" | head -1 |cut -d'"' -f4)"
fi
if [[ -n $version_status ]]; then
printable_version_status=" ($version_status)"
fi
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_joomla() {
#Joomla3.x
if [[ ! -f "$docroot/index.html" ]] && [[ -n "$(grep -s 'Joomla.Site' $docroot/index.php)" ]];then
cms='Joomla'
if [[ -f "$docroot/libraries/src/Version.php" ]]; then
minor_version=".$(grep 'const MINOR_VERSION' $docroot/libraries/src/Version.php |egrep -o '[0-9]{1,2}')"
patch_version=".$(grep 'const PATCH_VERSION' $docroot/libraries/src/Version.php |egrep -o '[0-9]{1,2}')"
version="3$minor_version$patch_version"
elif [[ ! -f "$docroot/index.html" ]] && [[ -n "$(grep -s 'Joomla.Site' $docroot/index.php)" ]] && [[ -n "$(grep -s 'public $RELEASE =' "$docroot/libraries/cms/version/version.php" |grep 2)" ]]; then
minor_version=".$(grep -s 'public $DEV_LEVEL =' "$docroot"/libraries/cms/version/version.php | egrep -o '[0-9]{1,2}')"
version="2.5$minor_version"
else
version=''
fi
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_drupal() {
if [[ ! -f "$docroot/index.html" ]] && [[ -n "$(grep -s 'The PHP page that serves all page requests on a Drupal installation' $docroot/index.php)" ]];then
cms='Drupal'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_magento() {
#Magento
if [[ ! -f "$docroot/index.html" ]] && [[ -n "$(egrep -si "Copyright.*Magento, Inc" $docroot/index.php)" ]];then
cms='Magento'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_whmcs() {
#WHMCS
if [[ ! -f "$docroot/index.html" ]] && [[ -n "$(egrep -si "WHMCS - The Complete Client Management, Billing & Support Solution" $docroot/index.php)" ]];then
cms='WHMCS'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_prestashop() {
#Prestashop
if [[ ! -f "$docroot/index.html" ]] && [[ -n "$(egrep -si '@author[[:blank:]]*PrestaShop SA' $docroot/index.php)" ]];then
cms='PrestaShop'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_phpbb() {
#PHPBB
if [[ ! -f "$docroot/index.html" ]] && [[ -n "$(egrep -si "PHPBB_ROOT_PATH" $docroot/index.php)" ]];then
cms='phpBB'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
for cms_check in checkif_wordpress checkif_joomla checkif_drupal checkif_magento checkif_whmcs checkif_prestashop checkif_phpbb
do $cms_check
done
if [[ -z "$cms" ]]; then
cms='unknown'
fi
#Only print CMS if defined
#Version is empty unless found by the wordpress or joomla check
if [[ ! "$cms" == 'unknown' ]]; then
printf "CMS:\t\t$cms $version${printable_version_status}\n"
fi
echo
vhost_includes=$(ls ${user_homedir}/var/${domain}/apache/*.conf 2> /dev/null)
if [[ -n $vhost_includes ]]; then
for include in $vhost_includes ; do
printf "VHOST INCLUDE:\t$include\n"
done
echo
fi
whodat_verbose_iwx() {
#Add some verbose stuff. Everything from this point on only shows if --verbose or -v is called
if [[ "$run_verbose" = '1' ]]; then
echo 'Crontab:================================================================'
echo
#Display user's crons
crontab -u $user -l
echo
run_logs=1
run_iwx_logs
fi
} #end whodat_verbose_iwx
run_iwx_logs() {
if [[ "$run_logs" = '1' ]]; then
#Print log locations
echo 'Logs:==================================================================='
echo
printf "Apache Error Logs:\t ${user_homedir}/var/${domain}/logs/error-ssl.log\n"
printf "\t\t\t ${user_homedir}/var/${domain}/logs/error.log\n"
printf "\t\t\t /var/log/httpd/ssl_error_log\n"
printf "\t\t\t /var/log/httpd/error_log\n"
printf "Apache Domlogs:\t\t ${user_homedir}/var/${domain}/logs/transfer-ssl.log\n"
printf "\t\t\t ${user_homedir}/var/${domain}/logs/transfer.log\n"
if [[ -n $(echo $php_ver |grep -i 'system default') ]]; then
printf "PHP-FPM Error Log:\t /var/log/php-fpm/error.log\n"
fi
if [[ -n $(echo $php_ver |grep -i 'Remi') ]]; then
php_short_ver=$(echo $php_ver |egrep -io 'PHP [[:digit:]]\.[[:digit:]]' |tr [:upper:] [:lower:] |tr -d ' ' | tr -d '.')
if [[ -n $(echo $php_short_ver |grep 'php5') ]]; then
printf "PHP-FPM Error Log:\t /opt/remi/${php_short_ver}/root/var/log/php-fpm/error.log\n"
fi
if [[ -n $(echo $php_short_ver |grep 'php7') ]]; then
printf "PHP-FPM Error Log:\t /var/opt/remi/${php_short_ver}/log/php-fpm/error.log\n"
fi
fi
mysql_error_log="$(mysqladmin -s variables | grep log_error |awk '{print $4}')"
if [[ -e $mysql_error_log ]]; then
printf "MySQL Error Log:\t $mysql_error_log\n"
fi
if [[ -e ${user_homedir}/var/${domain}/logs/letsencrypt.log ]]; then
printf "AutoSSL/LetsEncrypt Log: ${user_homedir}/var/${domain}/logs/letsencrypt.log\n"
fi
printf "FTP Login Log:\t\t /var/log/proftpd/auth.log\n"
printf "FTP Transfer Log:\t /var/log/proftpd/xfer.log\n"
printf "SSH/SFTP Log: \t\t /var/log/secure\n"
echo
fi
} #end iwx_logs
run_iwx_logs
whodat_verbose_iwx
} #end run_iwx
#=====================================================================================================================================
#=====================================================================================================================================
#INTERWORX ENDS HERE
#=====================================================================================================================================
#=====================================================================================================================================
#BEGIN PLESK
#=====================================================================================================================================
run_plesk() {
#Handle arguments passed to the script
flags="$(echo " $@" | egrep -o '[[:blank:]]-.*([[:blank:]]|$)')"
#Retrieve the domain name or username from the search. Basically pull any passed arguments that don't start with -
search="$(echo " $@" | egrep -o '[[:blank:]](https?://|)[[:alnum:]]([[:alnum:]]|-|\.|/|\?|\&|_)*([[:blank:]]|$)' | awk '{print $1}')"
#echo flags: $flags
#echo search: $search
#echo raw args :$@
#check for -v or --verbose being called
if [[ -n $(echo "$flags" |egrep -- '[[:blank:]]-[[:alpha:]]?v|[[:blank:]]--verbose') ]];then
run_verbose=1
fi
#check for -l or --logs being called
if [[ -n $(echo "$flags" |egrep -- '[[:blank:]]-[[:alpha:]]?l|[[:blank:]]--logs') ]];then
run_logs=1
fi
usage () {
printf "Usage: whodat [Flags] [Domain]\n"
printf "Flags:\n\t-h, --help\tShow this help message.\n"
printf "\t-l, --logs\tInclude the location of some of the relevant logs in the output."
printf "\t-v, --verbose\tShows verbose information about the domain or user.\n\n"
}
if [[ -n $(echo "$flags" |egrep -- '[[:blank:]]-[[:alpha:]]?h|[[:blank:]]--help') ]];then
usage
exit 0
fi
if [[ -z $search ]]; then
echo "Error: No domain specified!"
return 1
fi
#Convert any UPPERCASE to lowercase from input.
if [[ -n $(echo $search |egrep '[[:upper:]]') ]]; then
search="$(echo "$search" | tr '[:upper:]' '[:lower:]' )"
fi
#Strip the http protocol from the domain:
if [[ -n $(echo "$search" |egrep '^https?://') ]]; then
search="$(echo "$search" | sed -r 's#^https?://##')"
fi
#Strip www. from the beginning of the domain:
if [[ -n $(echo "$search" |egrep '^www\.') ]]; then
search="$(echo "$search" | sed 's/^www\.//')"
fi
#Remove trailing slash or any URI (if copied from browser, or specific uri supplied)
if [[ -n $(echo "$search" |egrep '/') ]]; then
search="$(echo "$search" | sed -r 's#/.*$##')"
fi
#Check to see if the domain exists
if [[ -z "$(/usr/local/psa/bin/domain -l |egrep "^$search$")" ]]; then
printf "[Error] $search not listed in plesk, see: '/usr/local/psa/bin/domain -l' "
return 1
else
domain="$search"
fi
#Get docroot, user and IP, store as variable to reference later on
plesk_docroot_user_ip_call="$(plesk bin site --info $domain |egrep -i '(^--WWW-Root--|^FTP Login:|^IP address:)' )"
docroot="$(echo "$plesk_docroot_user_ip_call" |egrep '^--WWW-Root--' |awk '{print $2}')"
user="$(echo "$plesk_docroot_user_ip_call" |egrep '^FTP Login:' |awk '{print $3}')"
user_homedir="$(readlink -f $(eval echo "~${user}"))"
plesk_ip="$(echo "$plesk_docroot_user_ip_call" |egrep -i '^IP address:' |awk '{print $3}')"
#resolve the A record
a_record=$(dig +short $domain @8.8.8.8 | egrep '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$')
if [[ -z $a_record ]] ; then
a_record="${bold}MISSING!${normal}"
fi
#Check for a AAAA DNS record. With some regex that is way more complicated than I'd like. Source: https://stackoverflow.com/a/17871737
AAAA_record=$(dig +short AAAA $domain @8.8.8.8| egrep '(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))')
#Grab the PHP version and handler from the psa database
php_handler=$(plesk db -bse "select h.php_handler_id from domains d join hosting h on h.dom_id=d.id where name = '$domain'")
#If the version isn't specified, that means it's using the default, which we can grab with `php -v`
if [[ -z $(echo $php_handler |egrep 'php[0-9]{2}') ]]; then
php_version="$(php -v 2>/dev/null |egrep '^PHP [0-9]' | awk '{print $2}')"
#If the version isn't specified, that means its using the default, which we can grab with `php -v`
php_printout="php-$php_version-$php_handler"
else
php_printout="$php_handler"
fi
#Check for Common CMS signatures.
#Each of these checks basically make sure there is no index.html (which historically had a higher priority index file than index.php)
#And checks for common strings of code that would identify a particular CMS
checkif_wordpress() {
#Wordpress
if [[ ! -f "$docroot/index.html" ]] && [[ -f "$docroot/index.php" ]] && [[ -n "$(grep -s 'Front to the WordPress application' $docroot/index.php)" ]]; then
cms='WordPress'
#Get the wp version if we can
version="$(grep -s '^\$wp_version' "$docroot/wp-includes/version.php" |cut -d\' -f2)"
#Check the security status of the installed wp version. This will mention if the wordprress version is up-to-date, outdated, or insecure.
if [[ -n "$version" ]]; then
version_status="$(curl -s http://api.wordpress.org/core/stable-check/1.0/ |grep "\"$version\"" | head -1 |cut -d'"' -f4)"
fi
if [[ -n $version_status ]]; then
printable_version_status=" ($version_status)"
fi
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_joomla() {
#Joomla3.x
if [[ -n "$(grep -s 'Joomla.Site' $docroot/index.php)" ]];then
cms='Joomla'
if [[ -f "$docroot/libraries/src/Version.php" ]]; then
minor_version=".$(grep 'const MINOR_VERSION' $docroot/libraries/src/Version.php |egrep -o '[0-9]{1,2}')"
patch_version=".$(grep 'const PATCH_VERSION' $docroot/libraries/src/Version.php |egrep -o '[0-9]{1,2}')"
version="3$minor_version$patch_version"
elif [[ ! -f "$docroot/index.html" ]] && [[ -n "$(grep -s 'Joomla.Site' $docroot/index.php)" ]] && [[ -n "$(grep -s 'public $RELEASE =' "$docroot/libraries/cms/version/version.php" |grep 2)" ]]; then
minor_version=".$(grep -s 'public $DEV_LEVEL =' "$docroot"/libraries/cms/version/version.php | egrep -o '[0-9]{1,2}')"
version="2.5$minor_version"
else
version=''
fi
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_drupal() {
if [[ -n "$(grep -s 'The PHP page that serves all page requests on a Drupal installation' $docroot/index.php)" ]];then
cms='Drupal'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_magento() {
#Magento
if [[ -n "$(egrep -si "Copyright.*Magento, Inc" $docroot/index.php)" ]];then
cms='Magento'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_whmcs() {
#WHMCS
if [[ -n "$(egrep -si "WHMCS - The Complete Client Management, Billing & Support Solution" $docroot/index.php)" ]];then
cms='WHMCS'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_prestashop() {
#Prestashop
if [[ -n "$(egrep -si '@author[[:blank:]]*PrestaShop SA' $docroot/index.php)" ]];then
cms='PrestaShop'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
checkif_phpbb() {
#PHPBB
if [[ -n "$(egrep -si "PHPBB_ROOT_PATH" $docroot/index.php)" ]];then
cms='phpBB'
return 63 #Exit the loop and don't check for other CMS's if we've identified one
fi
}
for cms_check in checkif_wordpress checkif_joomla checkif_drupal checkif_magento checkif_whmcs checkif_prestashop checkif_phpbb
do $cms_check
done
if [[ -z "$cms" ]]; then
cms='unknown'
fi
#Print the info:
printf "\nUsername:\t$user\n"
printf "${bold}Docroot:\t$docroot${normal}\n"
printf "Domain:\t\t$domain\n"
printf "Configured IP:\t$plesk_ip\n"
#If there are more than 1 A record, print each one on a new line
for ip in $a_record ; do
printf "A Record:\t$ip\n"
done
#Only print the ipv6 AAAA records if they exist
#And print one on each line if there are more than 1
if [[ -n $AAAA_record ]];then
for ipv6 in $AAAA_record ; do
printf "AAAA Record:\t$ipv6\n"
done
fi
printf "PHP:\t\t$php_printout\n"
#Only print CMS if defined Version is empty unless found by the wordpress or joomla check
if [[ ! "$cms" == 'unknown' ]]; then
printf "CMS:\t\t$cms $version${printable_version_status}\n"
fi
echo
run_plesk_logs() {
if [[ "$run_logs" = '1' ]]; then
#Print log locations
echo 'Logs:==================================================================='
echo
printf "Apache Error Logs:\t ${user_homedir}/logs/error.log\n"
printf "\t\t\t /var/log/httpd/error_log\n"
if [[ -e ${user_homedir}/logs/proxy_error_log ]]; then
printf "Proxy Error Log:\t ${user_homedir}/logs/proxy_error_log\n"
fi
printf "Apache Domlogs:\t\t ${user_homedir}/logs/access.log\n"
printf "\t\t\t ${user_homedir}/logs/access_ssl_log\n"
if [[ -n $(echo "$php_printout" |grep -i fpm) ]]; then
printf "PHP-FPM Log:\t\t /var/log/${php_printout}/error.log\n"
fi
mysql_error_log="$(mysqladmin -u admin -p$(cat /etc/psa/.psa.shadow) -s variables | grep log_error |awk '{print $4}')"
if [[ -e $mysql_error_log ]]; then
printf "MySQL Error Log:\t $mysql_error_log\n"
fi
printf "FTP Log:\t\t /var/log/plesk/xferlog*\n"
printf "SSH/SFTP Log: \t\t /var/log/secure\n"
echo
fi
}
whodat_verbose_plesk() {
#Add some verbose stuff. Everything from this point on only shows if --verbose or -v is called
if [[ "$run_verbose" = '1' ]]; then
echo 'Crontab:================================================================'
echo
#Display user's crons
crontab -u $user -l
echo
run_logs=1
run_plesk_logs
fi
} #end whodat_verbose_plesk
run_plesk_logs
whodat_verbose_plesk
} # end run_plesk
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment