File: //usr/share/imunify360-webshield/webshieldctl
#!/bin/bash
if [ "$IM360_DEBUG_SHELL" = "1" ]; then
echo "IM360_ARGV: <$0 [$@]>"
set -x
else
:
fi
# For backwards compatibility with CentOS 6 only.
WEBSHIELD='imunify360-webshield'
JOBFILE=/etc/cron.d/imunify360-webshield-check
STATEFILE="/usr/share/imunify360-webshield/.webshieldctl.status"
VIRTSERVER_CONF="/etc/imunify360-webshield/virtserver.conf"
WEBSHIELD_ANTIBOT_CONF="/etc/imunify360-webshield/splashscreen-antibot.conf"
MODE='undefined'
SSL_UNIT='imunify360-webshield-ssl-cache'
WAFD_UNIT='imunify360-wafd'
MAIN_UNIT='undefined'
OUR_MODULES_DIR=/usr/share/imunify360-webshield/modules
NGINX_MODULE_CONF=/etc/nginx/modules-enabled/40-imunify360-access-checker.conf
NGINX_CHECKER_CONF=/etc/nginx/conf.d/imunify360-access-checker.conf
load_mode() {
local mode='undefined'
local unit='undefined'
local value=''
local cfg=/usr/share/imunify360-webshield/modularity_mode
[ -s "$cfg" ] && value=$(<"$cfg")
case "$value" in
nginx)
mode="$value"
unit="$value"
;;
*)
mode='standalone'
unit='imunify360-webshield'
;;
esac
export MODE="$mode"
export MAIN_UNIT="$unit"
}
is_standalone() {
[ "$MODE" = 'standalone' ]
}
cleanup_configs() {
case "$MODE" in
nginx)
rm -vf "$NGINX_MODULE_CONF" "$NGINX_CHECKER_CONF"
;;
esac
}
prepare_nginx() {
local version=$(nginx -v 2>&1 | grep -oP '(\d+[.]){2}\d+')
local mod_path="$OUR_MODULES_DIR"/"ngx_http_access_checker_module_${version}.so"
if ! [ -s "$mod_path" ]; then
echo "ERROR: Unable to find nginx module for version '$version'." >&2
return 1
fi
# WARN: Explicit check that the path is exist and it is a directory
# cause simple 'echo' to a file will raise error with an ambiguous message
# "No such file or directory" like you're trying to *READ* from the file.
# "dirname" does not check type of its argument and just cut everything
# following the last slash.
local path=''
for path in "$NGINX_MODULE_CONF" "$NGINX_CHECKER_CONF"; do
if ! [ -d $(dirname "$path") ]; then
echo "ERROR: Unable to find directory for config '$path'." >&2
return 1
fi
done
if ! nginx -t ; then
echo "ERROR: Invalid nginx config before installing module." >&2
return 1
fi
echo "load_module ${mod_path};" >| "$NGINX_MODULE_CONF" || return 1
echo 'access_checker unix:/var/run/imunify360/libiplists-daemon.sock;' >| "$NGINX_CHECKER_CONF" || return 1
if ! nginx -t ; then
echo "ERROR: Invalid nginx config after installing module." >&2
return 1
fi
}
prepare_configs() {
case "$MODE" in
nginx)
prepare_nginx
;;
esac
}
check_nginx() {
[ -s "$NGINX_MODULE_CONF" ] || return 1
[ -s "$NGINX_CHECKER_CONF" ] || return 1
nginx -T 2> /dev/null | grep -qE '^access_checker\s+unix:/[^.]+[.]sock;$' || return 1
local pid=''
pid=$(pgrep -f 'nginx:\s+master') || return 1
# pid=1 is acquired by init.
[[ "$pid" =~ ^([2-9]|[1-9][0-9]+)$ ]] || return 1
grep -qP '/ngx_http_access_checker_module_(\d+[.]){2}\d+[.]so$' /proc/"$pid"/maps
}
check_configs() {
case "$MODE" in
nginx)
check_nginx
;;
esac
}
has_hosting_panel(){
local checks=(
/usr/local/cpanel/cpanel
/usr/sbin/plesk
/usr/local/directadmin/custombuild/build
)
for i in ${checks[@]};do
[ -e $i ] && return 0
done
return 1
}
count_processes(){
local count=$(ps aux | grep -c '[i]m360:\|webshield-[s]sl-cache')
echo $count
}
check_running(){
# for hosts with hosting panels we expect 5 processes to be running.
# otherwise 4 ones (ssl-cache is not expected to be run on no-panel hosts)
local num=$(count_processes)
local expected
if has_hosting_panel; then expected=3; else expected=2; fi
[ $num -ge $expected ] && return 0
return 1
}
check_stopped(){
local num=$(count_processes)
[ $num -eq 0 ] && return 0
return 1
}
enable_for_systemd(){
systemctl enable $WAFD_UNIT || return $?
systemctl enable $SSL_UNIT || return $?
is_standalone || return 0
systemctl enable $MAIN_UNIT || return $?
}
start_for_systemd(){
systemctl start $WAFD_UNIT || return $?
if ! systemctl start $SSL_UNIT; then
# WARN: Ignore error cause ssl-cache will exit if there is no panel.
has_hosting_panel && return 1 || :
fi
if is_standalone; then
systemctl start $MAIN_UNIT
else
prepare_configs && systemctl reload $MAIN_UNIT && return 0
cleanup_configs
return 1
fi
}
activate_for_systemd(){
local RV
enable_for_systemd
RV=$?
[ $RV -ne 0 ] && return $RV
start_for_systemd
}
disable_for_systemd(){
local failed=0
# we don't disable wafd because it's used
# for ip-list functionality
systemctl disable $SSL_UNIT || failed=1
if is_standalone; then
systemctl disable $MAIN_UNIT || failed=1
else
cleanup_configs || failed=1
systemctl reload $MAIN_UNIT || failed=1
fi
return $failed
}
stop_for_systemd(){
local failed=0
local wafd_force=$1
# we stop wafd only in 'restart' action, i.e stop with
# subsequent start
if [ "x$wafd_force" = xforce ];then
systemctl stop $WAFD_UNIT || failed=1
fi
systemctl stop $SSL_UNIT || failed=1
if is_standalone; then
systemctl stop $MAIN_UNIT || failed=1
else
cleanup_configs || failed=1
systemctl reload $MAIN_UNIT || failed=1
fi
return $failed
}
deactivate_for_systemd(){
local RV
stop_for_systemd
RV=$?
[ $RV -ne 0 ] && return $RV
disable_for_systemd
}
enable_for_sysvinit(){
local RV
/sbin/chkconfig $WEBSHIELD on > /dev/null 2>&1
RV=$?
if [ $RV -ne 0 ];then
echo "Enabling $WEBSHIELD returned non-zero status" 1>&2
return $RV
fi
if [ -e $JOBFILE ];then
sed -i -e 's/^#//g' $JOBFILE
RV=$?
if [ $RV -ne 0 ];then
echo "Enabling cron job returned non-zero status" 1>&2
fi
fi
return $RV
}
start_for_sysvinit(){
local RV
/sbin/service $WEBSHIELD start >/dev/null 2>&1
RV=$?
if [ $RV -ne 0 ];then
echo "Starting $WEBSHIELD returned non-zero status" 1>&2
return $RV
fi
if [ -e $JOBFILE ];then
sed -i -e 's/^#//g' $JOBFILE
RV=$?
if [ $RV -ne 0 ];then
echo "Enabling cron job returned non-zero status" 1>&2
fi
fi
[ $RV -ne 0 ] && return $RV
check_running
}
activate_for_sysvinit(){
local RV
enable_for_sysvinit
RV=$?
[ $RV -ne 0 ] && return $RV
start_for_sysvinit
}
disable_for_sysvinit(){
local RV
for ITEM in $WEBSHIELD $SSL_CACHE;do
/sbin/chkconfig --del $ITEM > /dev/null 2>&1
RV=$?
if [ $RV -ne 0 ];then
echo "Disabling $ITEM returned non-zero status" 1>&2
return $RV
fi
done
if [ -e $JOBFILE ];then
sed -i -e 's/^\([^#]\)/#\1/g' $JOBFILE
RV=$?
if [ $RV -ne 0 ];then
echo "Disabling cron job returned non-zero status" 1>&2
fi
fi
return $RV
}
stop_for_sysvinit(){
local RV
for ITEM in $WEBSHIELD $SSL_CACHE;do
/sbin/service $ITEM stop >/dev/null 2>&1
RV=$?
if [ $RV -ne 0 ];then
echo "Stopping $ITEM returned non-zero status" 1>&2
return $RV
fi
done
if [ -e $JOBFILE ];then
sed -i -e 's/^\([^#]\)/#\1/g' $JOBFILE
RV=$?
if [ $RV -ne 0 ];then
echo "Disabling cron job returned non-zero status" 1>&2
fi
fi
[ $RV -ne 0 ] && return $RV
check_stopped
}
deactivate_for_sysvinit(){
local RV
stop_for_sysvinit
RV=$?
[ $RV -ne 0 ] && return $RV
disable_for_sysvinit
}
is_systemd(){
if [ -e "/etc/redhat-release" ];then
local version=$(cat /etc/redhat-release | sed -e 's/^[[:alpha:][:space:]]\+//' | head -c 1)
if [ "$version" = "6" ];then
echo "No"
return 0
fi
fi
echo "Yes"
}
do_enable(){
if [ "x$(is_systemd)" = "xYes" ];then
enable_for_systemd
else
enable_for_sysvinit
fi
local rv=$?
if [ $rv == 0 ]; then
echo "enabled" > $STATEFILE
fi
return $rv
}
do_disable(){
if [ "x$(is_systemd)" = "xYes" ];then
disable_for_systemd
else
disable_for_sysvinit
fi
local rv=$?
if [ $rv == 0 ]; then
echo "disabled" > $STATEFILE
fi
return $rv
}
do_start(){
if [ "x$(is_systemd)" = "xYes" ];then
start_for_systemd
else
start_for_sysvinit
fi
local rv=$?
if [ $rv == 0 ]; then
echo "started" > $STATEFILE
fi
return $rv
}
do_stop(){
local force=$1
if [ "x$(is_systemd)" = "xYes" ];then
stop_for_systemd $force
else
stop_for_sysvinit
fi
local rv=$?
if [ $rv == 0 ]; then
echo "stopped" > $STATEFILE
fi
return $rv
}
do_activate(){
if [ "x$(is_systemd)" = "xYes" ];then
activate_for_systemd
else
activate_for_sysvinit
fi
local rv=$?
if [ $rv == 0 ]; then
echo "activated" > $STATEFILE
fi
return $rv
}
do_deactivate(){
if [ "x$(is_systemd)" = "xYes" ];then
deactivate_for_systemd
else
deactivate_for_sysvinit
fi
local rv=$?
if [ $rv == 0 ]; then
echo "deactivated" > $STATEFILE
fi
return $rv
}
is_enabled_for_systemd(){
# We don't care if ssl-cache unit is enabled. Webshield will start it
# by 'Wants' dependency before its own start. If it's not required for
# given environment (no known hosting panel) it'll exit then.
local failed=0
if systemctl -q is-enabled $WAFD_UNIT; then
echo "Unit '$WAFD_UNIT' is enabled."
else
echo "ERROR: Unit '$WAFD_UNIT' is NOT enabled." >&2
failed=1
fi
# $MAIN_UNIT is either imunify360-webshield (in standalone mode) or a host
# webserver. It seems that there's no sense to check if host webserver is
# enabled as we don't have control over it at any rate.
if is_standalone; then
if systemctl -q is-enabled $MAIN_UNIT; then
echo "Unit '$MAIN_UNIT' is enabled."
else
echo "Unit '$MAIN_UNIT' is NOT enabled." >&2
failed=1
fi
else
systemctl -q is-enabled $WEBSHIELD
failed=$?
fi
return $failed
}
is_enabled_for_sysvinit(){
local _runlevel=$(runlevel|cut -d' ' -f2)
local STATE=$(LANG=C /sbin/chkconfig --list $WEBSHIELD 2>/dev/null | grep "$_runlevel:on")
if [ -n "$STATE" ];then
echo "$WEBSHIELD is enabled"
return 0
else
echo "$WEBSHIELD is disabled"
return 1
fi
}
is_enabled(){
if [ "x$(is_systemd)" = "xYes" ];then
is_enabled_for_systemd
else
is_enabled_for_sysvinit
fi
}
is_active(){
# For CentOS 6 compatibility.
if ! [ "x$(is_systemd)" = "xYes" ]; then
if ! check_running; then
echo "$WEBSHIELD is not running"
return 1
fi
echo "$WEBSHIELD is running"
return 0
fi
if is_standalone; then
if check_running; then
echo "$MAIN_UNIT is running"
return 0
else
echo "$MAIN_UNIT is not running"
return 1
fi
fi
local name='undefined'
local state='undefined'
local units=($MAIN_UNIT $WAFD_UNIT $SSL_UNIT)
local failed=0
for name in ${units[@]}; do
state="$(systemctl is-active $name 2>&1)"
if [ "$state" = "active" ]; then
echo "Unit '$name' is active."
else
# WARN: ssl-cache must be processed in its very special way, see below.
if ! [ "$name" = $SSL_UNIT ]; then
echo "ERROR: Unit '$name' is NOT active, result='$state'." >&2
failed=1
continue
fi
if has_hosting_panel; then
echo "ERROR: Unit '$SSL_UNIT' is NOT active, result '$state'." >&2
failed=1
else
echo "WARNING: Unit '$SSL_UNIT' is NOT active, result '$state' (ignored)." >&2
fi
fi
done
if [ $failed -eq 0 ]; then
if ! check_configs; then
echo "ERROR: Web server is not configured properly." >&2
failed=1
fi
fi
return $failed
}
do_restart(){
do_stop force
do_start
}
do_enable_splashscreen(){
is_standalone || return 0
local ss_state=$(awk '$1 == "splashscreen_antibot" {gsub(";","",$2);print $2}' $WEBSHIELD_ANTIBOT_CONF)
if [ "$ss_state" = on ];then
echo "splashscreen is already enabled"
return 0
fi
sed -i -e "/splashscreen_antibot/ {s/off/on/}" $WEBSHIELD_ANTIBOT_CONF
do_restart
}
do_disable_splashscreen(){
is_standalone || return 0
local ss_state=$(awk '$1 == "splashscreen_antibot" {gsub(";","",$2);print $2}' $WEBSHIELD_ANTIBOT_CONF)
if [ "$ss_state" = off ];then
echo "splashscreen is already disabled"
return 0
fi
sed -i -e "/splashscreen_antibot/ {s/on/off/}" $WEBSHIELD_ANTIBOT_CONF
do_restart
}
do_enable_cpanelprotection(){
is_standalone || return 0
local cp_state=$(awk '$2 == "$cpanel_protection" {gsub(";","",$3);print $3}' $VIRTSERVER_CONF)
if [ "$cp_state" = 1 ];then
echo "cpanel_protection is already enabled"
return 0
fi
sed -i -e '/$cpanel_protection/ {s/0/1/}' $VIRTSERVER_CONF
do_restart
}
do_disable_cpanelprotection(){
is_standalone || return 0
local cp_state=$(awk '$2 == "$cpanel_protection" {gsub(";","",$3);print $3}' $VIRTSERVER_CONF)
if [ "$cp_state" = 0 ];then
echo "cpanel_protection is already disabled"
return 0
fi
sed -i -e '/$cpanel_protection/ {s/1/0/}' $VIRTSERVER_CONF
do_restart
}
do_reload(){
if [ "x$(is_systemd)" = "xYes" ];then
# WARN: Ignoring errors here is for the compatibility with sysvinit script
# which contains bug - on action "reload" it always exits with code 0.
# try-reload-or-restart is supported only from version 229,
# which is not the case for Centos7. The difference between try-reload-or-restart
# and reload-or-restart is that former does nothing unless the service is running.
if systemctl --quiet is-active $SSL_UNIT;then
systemctl reload-or-restart $SSL_UNIT || :
fi
if systemctl --quiet is-active $WAFD_UNIT;then
systemctl reload-or-restart $WAFD_UNIT || :
fi
if systemctl --quiet is-active $MAIN_UNIT;then
systemctl reload-or-restart $MAIN_UNIT || :
fi
else
# On attempt to reload stopped webshield we get error 7
# which crashes imunify360 reloader. So let's first make sure
# webshield is running and do nothing otherwise
if service $WEBSHIELD status >/dev/null 2>&1;then
service $WEBSHIELD reload
fi
fi
}
print_help(){
echo "enable : enables webshield starting on boot (without actully starting it)"
echo "is-enabled : shows if the webshield is enabled to start on boot"
echo "is-active : shows if the webshield is running now"
echo "disable : disables webshield starting on boot (without actully stopping it)"
echo "start : starts webshield (without enabling its starting on boot)"
echo "stop : stops webshield (without disabling its starting on boot)"
echo "activate : enables webshield starting on boot and starts it right away"
echo "deactivate : stops webshield right away and disables its starting on boot"
echo "enable-splashscreen : enables splashscreen functionality for webshield"
echo "disable-splashscreen : disables splashscreen functionality for webshield"
echo "enable-cpanelprotection : enables cpanelprotection functionality for webshield"
echo "disable-cpanelprotection : disables cpanelprotection functionality for webshield"
echo "reload : reload settings without restart"
}
load_mode
case "$1" in
enable)
do_enable
;;
disable)
do_disable
;;
is-enabled)
is_enabled
;;
is-active)
is_active
;;
start)
do_start
;;
stop)
do_stop
;;
activate)
do_activate
;;
deactivate)
do_deactivate
;;
enable-splashscreen)
do_enable_splashscreen
;;
disable-splashscreen)
do_disable_splashscreen
;;
enable-cpanelprotection)
do_enable_cpanelprotection
;;
disable-cpanelprotection)
do_disable_cpanelprotection
;;
reload)
do_reload
;;
help)
print_help
;;
*)
echo "Usage: $0 {enable|disable|start|stop|activate|deactivate|is-enabled|is-active|enable-splashscreen|disable-splashscreen|enable-cpanelprotection|disable-cpanelprotection|reload|help}"
exit 2
esac