This commit is contained in:
cutemeli
2025-12-22 10:35:30 +00:00
parent 0bfc6c8425
commit 5ce7ca2c5d
38927 changed files with 0 additions and 4594700 deletions

Binary file not shown.

View File

@@ -1,266 +0,0 @@
#!/usr/bin/env bash
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
# --- utility functions ---
p_echo()
{
echo "$@" >&2
}
write() {
local filename="$1"
local directory=`dirname "$filename"`
mkdirectory "$directory"
if [ "x$?" != "x0" ] ; then
ERROR=$?
p_echo "Can not create directory $directory"
return $ERROR
fi
# Check target file can be replaced
if [ -f "$filename" ] ; then
if [ ! -w "$filename" -o ! -r "$filename" ] ; then
p_echo "Can not read/write to $filename"
return 100
fi
fi
# Put new content into temporary file
local tmpfile
tmpfile=`mktemp "$filename".XXXXXX`
if [ "x$?" != "x0" -o ! -w "$tmpfile" ] ; then
p_echo "Can not create temporary file $tmpfile"
return 101
fi
# Correct owner & permissions
chown "$FILE_OWNERGROUP" "$tmpfile" && chmod "$FILE_PERMS" "$tmpfile"
cat > "$tmpfile"
if [ "x$?" != "x0" ] ; then
p_echo "Error writing to $tmpfile"
rm -f "$tmpfile"
return 101
fi
# Check that new file is not empty
if [ ! -s "$tmpfile" ] ; then
p_echo "No or empty input supplied on utility's standard input stream!"
rm -f "$tmpfile"
return 101
fi
# Commit changes to target file (disable interactivity in mv)
mv -f "$tmpfile" "$filename"
if [ "x$?" != "x0" ] ; then
ERROR=$?
rm -f "$tmpfile"
return $ERROR
fi
return $?
}
mklink() {
if ! echo "$1" | grep -q ':' 2>/dev/null; then
p_echo "Invalid format for mklink: wait source:destinstation, got $1"
return 102
fi
local filename="${1%%:*}"
local destination="${1#*:}"
local directory=`dirname "$filename"`
local destination_directory=`dirname "$destination"`
if ! [ -d "$directory" -a -f "$filename" ]; then
p_echo "Path $filename doesn't exist"
return 100
fi
if [ ! -d "$destination_directory" ]; then
p_echo "Destination directory '$destination_directory' not exist"
return 100
fi
if [ -f "$destination" -a ! -L "$destination" ]; then
p_echo "Refusing to create symlink '$destination': file with the same name already exists"
return 101
fi
local fname=`basename "$filename"`
local lnkname="last_${fname#*_}"
# Create convenience symlink to last written config
pushd "$directory"
if [ ! -f "$lnkname" -o -L "$lnkname" ] ; then
ln -snfT "$fname" "$lnkname"
else
p_echo "Refusing to create symlink '$directory/$lnkname': file with the same name already exists"
ERROR=101
fi
popd
# Create symlink for argument
ln -snfT "$filename" "$destination"
local tmp_err="$?"
[ "$tmp_err" = "0" ] || ERROR="$tmp_err"
return $ERROR
}
mkdirectory() {
local path="$1"
if [ -d "$path" ] ; then
return 0
fi
if [ -e "$path" ] ; then
p_echo "File $path already exists"
return 100
fi
mkdir "$path"
if [ "x$?" != "x0" ] ; then
ERROR=$?
return $ERROR
fi
chmod "$DIR_PERMS" "$path"
if [ "x$?" != "x0" ] ; then
ERROR=$?
return $ERROR
fi
chown "$DIR_OWNERGROUP" "$path"
if [ "x$?" != "x0" ] ; then
ERROR=$?
return $ERROR
fi
return $?
}
check() {
local id file
while read data; do
if [ "x$data" != "x" ]; then
id=${data%%:*};
file=${data#*:};
if [ ! -f $file ]; then
echo "$id:File '$file' not found";
fi
fi
done
return 0
}
backup_file() {
local filename="$1"
[ ! -f "$filename" ] && return 0
cp -f "$filename" "$filename.bak"
chown "$FILE_OWNERGROUP" "$filename.bak" && chmod "$FILE_PERMS" "$filename.bak"
return $?
}
restore_file() {
local filename="$1"
[ ! -f "$filename.bak" ] && return 0
cp -f "$filename.bak" "$filename"
chown "$FILE_OWNERGROUP" "$filename" && chmod "$FILE_PERMS" "$filename"
return $?
}
#!/usr/bin/env bash
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
usage() {
cat << EOH
Usage: $0 [options]
Helper utility to manage Apache configuration files
OPTIONS:
-t - Test current configuration of web server.
-d dir - Create directory.
-w file - Write content from stdin to the specified file.
-b file - Create backup copy of specified file.
-r file - Restore backup copy of specified file if present.
-l file:destination - Switch or create symlink to the specified file
and switch or create 'last_*' symlink
-c - Read configuration files list from stdin and check their
their presence. Each line should be like '<id>:<filepath>'.
EOH
}
set_params()
{
DIR_OWNERGROUP="www-data":"psacln"
DIR_PERMS=770
FILE_OWNERGROUP="root":"www-data"
FILE_PERMS=600
}
# --- script ---
if [ $# -eq 0 ] ; then
usage
exit 0
fi
getopts "td:w:l:cb:r:" OPTION
set_params
ERROR=0
case $OPTION in
t)
[ ! -e "/etc/apache2/envvars" ] || source /etc/apache2/envvars
/usr/sbin/apache2ctl -t
ERROR=$?
;;
d)
mkdirectory "$OPTARG"
ERROR=$?
;;
w)
write "$OPTARG"
ERROR=$?
;;
l)
mklink "$OPTARG"
ERROR=$?
;;
c)
check
ERROR=$?
;;
b)
backup_file "$OPTARG"
ERROR=$?
;;
r)
restore_file "$OPTARG"
ERROR=$?
;;
*)
usage
ERROR=1
;;
esac
exit $ERROR
#
# Helper utility for file operations with Apache's configuration files.
#

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,55 +0,0 @@
#!/bin/bash
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
PN=`basename $0`
usage()
{
cat <<-EOL
Usage: $PN [--interactive [--verbose] ] [--fast] <boostrapper repair options>
Options:
-i, --interactive
run bootstrapper repair in interactive mode, do not supress stdout, stderr
-f, --fast
skip some time-consuming repair actions
-v, --verbose
verbose output from 'bootstrapper repair'
-h, --help
show this help
EOL
}
#parse options
TEMP=`getopt -o ifvh --long interactive,fast,verbose,help \
-n "$PN" -- "$@"`
if [ $? != 0 ] ; then echo "Internal error: failed to run getopt" >&2 ; exit 1 ; fi
eval set -- "$TEMP"
opt_interactive=0
opt_fast=0
opt_verbose=0
while true ; do
case "$1" in
-i|--interactive) opt_interactive=1; shift;;
-f|--fast) opt_fast=1; shift;;
-v|--verbose) opt_verbose=1; shift;;
-h|--help) usage; exit 0;;
--) shift ; break ;;
*) echo "Internal error!" ; exit 1 ;;
esac
done
if [ "$opt_fast" -gt 0 ]; then
export PLESK_INSTALLER_FAST_REPAIR=1
export PLESK_INSTALLER_SKIP_MCHK=1
fi
if [ "$opt_interactive" -gt 0 ]; then
[ ! "$opt_verbose" -gt 0 ] || export PLESK_INSTALLER_VERBOSE=1
/opt/psa/bootstrapper/pp18.0.74-bootstrapper/bootstrapper.sh repair "$@"
else
nohup /opt/psa/bootstrapper/pp18.0.74-bootstrapper/bootstrapper.sh repair "$@" >/dev/null 2>&1 &
fi

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,382 +0,0 @@
#!/bin/bash
### Copyright 1999-2023. Plesk International GmbH. All rights reserved.
# vim:ft=sh:
set -e
usage()
{
if [ -n "$*" ]; then
echo "drwebmng: $*" >&2
echo "Use '--help' option to get help on the utility usage" >&2
exit 2
fi
cat <<-EOT
Usage: drwebmng COMMAND [OPTIONS]
--add-check --mailname=<mail1,mail2,...> --type={"from"|"to"|"any"|"incoming"|"outgoing"} [--no-restart-service]
Add rule check into antivirus configuration file
--remove-check --mailname=<mail1,mail2,...> [--no-restart-service]
Delete rule check from antivirus configuration file
-p, --start Start drweb service
-o, --stop Stop drweb service
-s, --status Show drweb service status
-r, --restart Restart drweb service
-l, --reload Reload drweb service
-e, --on Turn on drweb
-d, --off Turn off drweb
-u, --update Reload, turn on or turn off drweb depending on the handlers state
-t, --setup-trial-vhost Set up support for drweb trial license in sw-cp-server
-h, --help Display this help and exit
EOT
exit 2
}
mail_handler_add()
{
local direction="$1"
local mailname="$2"
if [ "$direction" = "in" ]; then
"$MAIL_HANDLERS_BIN" --add --name "$DRWEB_HOOK_NAME" --mailname "$mailname" \
--priority "$DRWEB_HOOK_PRIORITY" --executable "$HOOK_DIR/$DRWEB_HOOK_NAME" \
--enabled --dont-preserve-on-restore \
--queue "before-queue" --type "recipient"
elif [ "$direction" = "out" ]; then
"$MAIL_HANDLERS_BIN" --add --name "$DRWEB_HOOK_NAME" --mailname "$mailname" \
--priority "$DRWEB_HOOK_PRIORITY" --executable "$HOOK_DIR/$DRWEB_HOOK_NAME" \
--enabled --dont-preserve-on-restore \
--queue "before-remote" --type "sender"
fi
}
mail_handler_remove()
{
local direction="$1"
local mailname="$2"
if [ "$direction" = "in" ]; then
"$MAIL_HANDLERS_BIN" --remove --name "$DRWEB_HOOK_NAME" --mailname "$mailname" \
--queue "before-queue" --type "recipient"
elif [ "$direction" = "out" ]; then
"$MAIL_HANDLERS_BIN" --remove --name "$DRWEB_HOOK_NAME" --mailname "$mailname" \
--queue "before-remote" --type "sender"
fi
}
mail_handler_set()
{
local direction="$1"
local mailname="$2"
if [ "$direction" = "none" ]; then
mail_handler_remove "in" "$mailname"
mail_handler_remove "out" "$mailname"
elif [ "$direction" = "any" ]; then
mail_handler_add "in" "$mailname"
mail_handler_add "out" "$mailname"
elif [ "$direction" = "incoming" -o "$direction" = "to" ]; then
mail_handler_add "in" "$mailname"
mail_handler_remove "out" "$mailname"
elif [ "$direction" = "outgoing" -o "$direction" = "from" ]; then
mail_handler_remove "in" "$mailname"
mail_handler_add "out" "$mailname"
fi
}
drweb_service()
{
local action="$1"
/bin/systemctl "$action" "$DRWEBD_SERVICE.service"
}
do_start()
{
drweb_service start
}
do_stop()
{
drweb_service stop
}
do_status()
{
if drweb_service is-active > /dev/null; then
echo "is running"
else
echo "is stopped"
fi
}
do_restart()
{
drweb_service restart
}
do_reload()
{
if drweb_service is-active > /dev/null; then
drweb_service reload
else
echo "Skip drweb antivirus daemon reloading - service is stopped" >&2
fi
}
setup_swcpserver()
{
local action="$1"
[ "$action" = "enable" -o "$action" = "disable" ]
if [ "$action" = "enable" ]; then
# allow TLSv1 connections in sw-cp-server if there is no key in the drwebd directory
[ ! -r "$DRWEB_SWCPSERVER_CONF" ] || return 0
cp -fT "$DRWEB_SWCPSERVER_CONF_TPL" "$DRWEB_SWCPSERVER_CONF"
# listen to ipv6 only if it is available
if [ -n "`cat /proc/net/if_inet6`" ]; then
cp -fT "$DRWEB_SWCPSERVER_IPV6_TPL" "$DRWEB_SWCPSERVER_IPV6"
fi
/usr/sbin/sw-cp-serverd -q -t && "$PLESKRC_BIN" sw-cp-server try-reload || {
echo "Unable to setup sw-cp-server to receive connections from drweb." >&2
rm -f "$DRWEB_SWCPSERVER_IPV6"
rm -f "$DRWEB_SWCPSERVER_CONF"
return 1
}
elif [ -r "$DRWEB_SWCPSERVER_CONF" ]; then
rm -f "$DRWEB_SWCPSERVER_IPV6"
rm -f "$DRWEB_SWCPSERVER_CONF"
"$PLESKRC_BIN" sw-cp-server try-reload
fi
}
register_service()
{
local action="$1"
[ "$action" = "enable" -o "$action" = "disable" ]
local REGISTER_SERVICE_BIN="$PRODUCT_ROOT_D/admin/sbin/register_service"
"$REGISTER_SERVICE_BIN" "--$action" "$DRWEBD_SERVICE" || {
echo "Unable to $action drweb antivirus daemon" >&2
return 1
}
}
watchdog_monit_service()
{
local action="$1"
[ "$action" = "monit" -o "$action" = "unmonit" ]
local WATCHDOG_BIN="$PRODUCT_ROOT_D/admin/bin/modules/watchdog/wd"
[ -x "$WATCHDOG_BIN" ] || {
echo "Skipped setting up monitoring in WatchDog as it is not accessible" >&2
return 0
}
"$WATCHDOG_BIN" "--$action-service=$DRWEB_WD_SERVICE" || {
echo "Unable to $action drweb in WatchDog" >&2
return 1
}
}
do_on()
{
do_setup_trial_vhost
register_service enable
do_start
watchdog_monit_service monit
}
do_off()
{
setup_swcpserver disable
watchdog_monit_service unmonit
do_stop
register_service disable
}
do_update()
{
local allow_reload="$1"
local ignore_current_state="$2"
local handlers_count="`
"$MAIL_HANDLERS_BIN" --list --json | python3 -c "
import sys, json
handlers = json.load(sys.stdin)['handlers']
print(sum(1 for h in handlers if h['name'] == '$DRWEB_HOOK_NAME' and h['enabled']))
"
`"
local was_running=
! drweb_service is-active > /dev/null || was_running="yes"
local needs_to_be_running=
! [ "$handlers_count" -gt 0 ] || needs_to_be_running="yes"
if [ "$was_running" != "$needs_to_be_running" -o -n "$ignore_current_state" ]; then
if [ -n "$needs_to_be_running" ]; then
do_on
else
do_off
fi
fi
if [ -n "$allow_reload" -a -n "$was_running" -a -n "$needs_to_be_running" ]; then
drweb_service reload
fi
}
do_setup_trial_vhost()
{
setup_swcpserver "`[ -r "$DRWEB_KEY" ] && echo disable || echo enable`"
}
# --- environment and constants setup ---
unset GREP_OPTIONS
umask 022
PRODUCT_ROOT_D='/opt/psa'
MAIL_HANDLERS_BIN="$PRODUCT_ROOT_D/admin/sbin/mail_handlers_control"
PLESKRC_BIN="$PRODUCT_ROOT_D/admin/sbin/pleskrc"
DRWEBD_SERVICE=drwebd
DRWEB_HOOK_NAME='drweb'
DRWEB_HOOK_PRIORITY='20'
DRWEB_KEY='/opt/drweb/drweb32.key'
DRWEB_SWCPSERVER_CONF='/etc/sw-cp-server/conf.d/plesk-drweb-local.conf'
DRWEB_SWCPSERVER_CONF_TPL='/etc/drweb/swcpserver.plesk-drweb-local.conf.tpl'
DRWEB_SWCPSERVER_IPV6='/etc/sw-cp-server/conf.d/plesk-drweb-local.ipv6.inc'
DRWEB_SWCPSERVER_IPV6_TPL='/etc/drweb/swcpserver.plesk-drweb-local.ipv6.inc.tpl'
DRWEB_WD_SERVICE='drweb'
HOOK_DIR='/opt/psa/handlers/hooks'
# --- parse args ---
opt_mailnames=()
opt_type=
opt_allow_restart="yes"
opt_cmd=
TEMP=`getopt -o posrleduth \
--long add-check,remove-check,mailname:,type:,no-restart-service,start,stop,status,restart,reload,on,off,update,setup-trial-vhost,help \
-n drwebmng -- "$@"` || exit 2
eval set -- "$TEMP"
declare -A CMD_SHORT_TO_LONG=(
[-p]=--start
[-o]=--stop
[-s]=--status
[-r]=--restart
[-l]=--reload
[-e]=--on
[-d]=--off
[-u]=--update
[-t]=--setup-trial-vhost
)
while [ "$#" -gt 0 ]; do
case "$1" in
-h|--help)
usage
;;
--mailname)
IFS=, opt_mailnames+=($2)
shift
;;
--type)
[ -z "$opt_type" ] || usage "Use '--type' only once"
opt_type="$2"
shift
;;
--no-restart-service)
opt_allow_restart=
;;
--add-check|--remove-check)
[ -z "$opt_cmd" ] || usage "Specify only one command, got '$opt_cmd' and '$1'"
opt_cmd="$1"
;;
--[a-z]*)
[[ "$1" =~ ^(`echo "${CMD_SHORT_TO_LONG[@]}" | tr " " "|"`)$ ]] ||
usage "Unrecognized option '$1'"
[ -z "$opt_cmd" ] || usage "Specify only one command, got '$opt_cmd' and '$1'"
opt_cmd="$1"
;;
-[a-z])
[[ "$1" =~ ^(`echo "${!CMD_SHORT_TO_LONG[@]}" | tr " " "|"`)$ ]] ||
usage "Unrecognized option '$1'"
[ -z "$opt_cmd" ] || usage "Specify only one command, got '$opt_cmd' and '$1'"
opt_cmd="${CMD_SHORT_TO_LONG[$1]}"
;;
--)
shift
break
;;
*)
usage "Unrecognized option '$1'"
;;
esac
shift
done
[ -z "$*" ] ||
usage "Positional arguments are not accepted"
[ -n "$opt_cmd" ] ||
usage "Command is empty"
[ "$opt_cmd" != "--add-check" ] || [ -n "${opt_mailnames[*]}" -a -n "$opt_type" ] ||
usage "Command '$opt_cmd' requires '--mailname' and '--type' options"
[ "$opt_cmd" != "--remove-check" ] || [ -n "${opt_mailnames[*]}" ] ||
usage "Command '$opt_cmd' requires '--mailname' option"
[ -n "$opt_allow_restart" ] || [ "$opt_cmd" = "--add-check" -o "$opt_cmd" = "--remove-check" ] ||
usage "Option '--no-restart-service' is accepted only by '--add-check' and '--remove-check' commands"
[ -z "$opt_type" ] || [ "$opt_type" = "from" -o "$opt_type" = "to" -o "$opt_type" = "any" \
-o "$opt_type" = "incoming" -o "$opt_type" = "outgoing" ] ||
usage "Unsupported '--type' option value: '$opt_type'"
# --- execute ---
case "$opt_cmd" in
--add-check)
for mailname in "${opt_mailnames[@]}"; do
mail_handler_set "$opt_type" "$mailname"
done
do_update "$opt_allow_restart"
;;
--remove-check)
for mailname in "${opt_mailnames[@]}"; do
mail_handler_set "none" "$mailname"
done
do_update "$opt_allow_restart"
;;
--start)
do_start
;;
--stop)
do_stop
;;
--status)
do_status
;;
--restart)
do_restart
;;
--reload)
do_reload
;;
--on)
do_on
;;
--off)
do_off
;;
--update)
do_update --allow-reload --ignore-current-state
;;
--setup-trial-vhost)
do_setup_trial_vhost
;;
esac

View File

@@ -1,105 +0,0 @@
#!/bin/bash
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
#
#
# Plesk script
#
#default values
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
# vim:syntax=sh
generate_encryption_key()
{
local key_file="/etc/psa/private/secret_key"
local key_dir="`dirname $key_file`"
local rc=0
[ -d "$key_dir" ] || mkdir -p "$key_dir"
if [ ! -e "$key_file" ]; then
dd if=/dev/urandom of="$key_file" bs=16 count=1 2>/dev/null
else
rc=1
fi
fix_key_permissions
return $rc
}
fix_key_permissions()
{
local key_file="/etc/psa/private/secret_key"
local key_dir="`dirname $key_file`"
if [ -e "$key_file" ]; then
chown psaadm:0 "$key_file"
chmod 0600 "$key_file"
fi
if [ -d "$key_dir" ]; then
chown psaadm:0 "$key_dir"
chmod 0700 "$key_dir"
fi
}
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
reexec_with_clean_env()
{
# Usage: call this function as 'reexec_with_clean_env "$@"' at the start of a script.
# Don't use with scripts that require sensitive environment variables.
# Don't put the call under any input/output redirection.
# Purpose: make sure the script is executed with a sane environment.
local lc="`get_default_locale`"
export LANG="$lc" LC_MESSAGES="$lc" LC_ALL="$lc"
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
umask 022
PLESK_SCRIPT_COMMAND_LINE="$0 $*"
[ -z "$PLESK_INSTALLER_ENV_CLEANED" ] || { unset PLESK_INSTALLER_ENV_CLEANED; return 0; }
[ -n "$BASH" ] || exec /bin/bash "$0" "$@"
# N.B.: the following code requires Bash. On Dash it would cause syntax error upon parse w/o eval.
eval '
local extra_vars=() # list of variables to preserve
for var in "${!PLESK_@}"; do # enumerate all PLESK_* variables
extra_vars+=("$var=${!var}")
done
extra_vars+=("PLESK_INSTALLER_ENV_CLEANED=1")
# Exec self with clean env except for extra_vars, shell opts, and arguments.
exec /usr/bin/env -i "${extra_vars[@]}" /bin/bash ${-:+-$-} "$0" "$@" || {
echo "Failed to reexec self ($0) with clean environment" >&2
exit 91 # Just some relatively unique error code
}
'
}
get_default_locale()
{
# Note that CentOS 7 typically doesn't have C.UTF-8
for lc in "C.UTF-8" "en_US.UTF-8" "C"; do
if [ -z "`LC_ALL=$lc locale 2>&1 >/dev/null`" ]; then
echo "$lc"
return 0
fi
done
echo "C"
}
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
# vim:ft=sh:
reexec_with_clean_env "$@"
key_file="/etc/psa/private/secret_key"
if [ -e "$key_file" ]; then
echo "Unable to generate new key - key file exists"
fix_key_permissions
exit 1
else
generate_encryption_key
fi

Binary file not shown.

Binary file not shown.

View File

@@ -1,38 +0,0 @@
#!/bin/bash
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
umask 022
output=`mktemp`
trap 'rm -f $output;' TERM INT EXIT
if [ -z "$output" ]; then
echo "Cannot create temporary file for execution" >&2
exit 1
fi
if [ -z "$1" ]; then
echo "URL not specified" >&2
exit 1
fi
http_code=`/usr/bin/curl -A "Plesk (fetch_url utility)" -sS -L -k -o "$output" -w "%{http_code}" "$1"`
if [ $? -ne 0 ]; then
echo "Unable to fetch URL: $1" >&2
exit 1
fi
# 2xx and 3xx are considered successful (however, 3xx shouldn't be present due to -L above)
rc=0
[ "$http_code" -ge 200 -a "$http_code" -lt 400 ] || rc=1
# In case of error all messages go to stderr
[ "$rc" -eq 0 ] || exec >&2
echo "Url '$1' fetched"
echo "Status: $http_code"
if [ -s "$output" ]; then
echo "Output:"
cat "$output"
fi
exit "$rc"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,7 +0,0 @@
#!/opt/psa/bin/sw-engine-pleskrun
<?php
die("The file {$_SERVER['SCRIPT_FILENAME']} is part of Plesk distribution. It cannot be run outside of Plesk environment.\n");
__sw_loader_pragma__('PLESK_18_0_59');
?>
<EFBFBD>&<11><><EFBFBD>.$+<2B>By<42><36>Y[:1d<31><64><1A>cl| <0B><><EFBFBD>=<3D>j<EFBFBD>Os<4F><73>{Ob<4F>99<1B><>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD>^<5E>kp<03><>p<EFBFBD>V+.)<29><>"<22><>l<EFBFBD><6C>,'{<1F>n<EFBFBD><6E>f/Tn<10><>MP<4D><12>D<><44><EFBFBD><EFBFBD>B<EFBFBD>Ǐf<C78F>{<7B>2Q<32>Wn<1E><>&<26><>#<0F><><EFBFBD>
C<EFBFBD>

Binary file not shown.

View File

@@ -1,7 +0,0 @@
#!/opt/psa/bin/sw-engine-pleskrun
<?php
die("The file {$_SERVER['SCRIPT_FILENAME']} is part of Plesk distribution. It cannot be run outside of Plesk environment.\n");
__sw_loader_pragma__('PLESK_18_0_59');
?>
<EFBFBD>&<11><><EFBFBD>.$+<2B>By<42><36>Y[:1d<31><64><1A>cl| <0B><><EFBFBD>=<3D>j<EFBFBD>Os<4F><73>{Ob<4F>99<1B><>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD>^<5E>kp<03><>p<EFBFBD>V+.)<29><>"<22><>l<EFBFBD><6C>,'{<1F>n<EFBFBD><6E>f/Tn<10><>MP<4D><12>D<><44><EFBFBD><EFBFBD>B<EFBFBD>Ǐf<C78F>{<7B>2Q<32>Wn<1E><>&<26><>#<0F><><EFBFBD>
C<EFBFBD>

View File

@@ -1,5 +0,0 @@
#!/bin/bash
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
if [ -e /var/run/proftpd.scoreboard ] ; then
exec /usr/bin/ftpwho -f /var/run/proftpd.scoreboard "$@"
fi

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,3 +0,0 @@
#!/bin/sh
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
exec /opt/psa/bin/sw-engine-pleskrun /opt/psa/admin/application/smb/utils/hostname-helper.php "$@"

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +0,0 @@
#!/opt/psa/bin/sw-engine-pleskrun
<?php
die("The file {$_SERVER['SCRIPT_FILENAME']} is part of Plesk distribution. It cannot be run outside of Plesk environment.\n");
__sw_loader_pragma__('PLESK_18_0_59');
?>
<EFBFBD>&<11><><EFBFBD>.$+<2B>By<42><36>Y[:1d<31><64><1A>cl| <0B><><EFBFBD>=<3D>j<EFBFBD>Os<4F><73>{Ob<4F>99<1B><>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD>^<5E>kp<03><>p<EFBFBD>V+.)<29><>"<22><>l<EFBFBD><6C>,'{<1F>n<EFBFBD><6E>f/Tn<10><>MP<4D><12>D<><44><EFBFBD><EFBFBD>B<EFBFBD>Ǐf<C78F>{<7B>2Q<32>Wn<1E><>&<26><>#<0F><><EFBFBD>
C<EFBFBD>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,468 +0,0 @@
#!/bin/bash
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
#
#
# Plesk script
#
#default values
product_default_conf()
{
PRODUCT_ROOT_D=/opt/psa
PRODUCT_RC_D=/etc/init.d
PRODUCT_ETC_D=/opt/psa/etc
PLESK_LIBEXEC_DIR=/usr/lib/plesk-9.0
HTTPD_VHOSTS_D=/var/www/vhosts
HTTPD_CONF_D=/etc/apache2
HTTPD_INCLUDE_D=/etc/apache2/conf-enabled
HTTPD_BIN=/usr/sbin/apache2
HTTPD_LOG_D=/var/log/apache2
HTTPD_SERVICE=apache2
QMAIL_ROOT_D=/var/qmail
PLESK_MAILNAMES_D=/var/qmail/mailnames
RBLSMTPD=/usr/sbin/rblsmtpd
NAMED_RUN_ROOT_D=/var/named/run-root
WEB_STAT=/usr/bin/webalizer
MYSQL_VAR_D=/var/lib/mysql
MYSQL_BIN_D=/usr/bin
MYSQL_SOCKET=/var/run/mysqld/mysqld.sock
PGSQL_DATA_D=/var/lib/postgresql/16/main
PGSQL_CONF_D=/etc/postgresql/16/main
PGSQL_BIN_D=/usr/lib/postgresql/16/bin
DUMP_D=/var/lib/psa/dumps
DUMP_TMP_D=/tmp
MAILMAN_ROOT_D=/usr/lib/mailman
MAILMAN_VAR_D=/var/lib/mailman
PYTHON_BIN=/usr/bin/python2
GPG_BIN=/usr/bin/gpg
TAR_BIN=/usr/lib/plesk-9.0/sw-tar
AWSTATS_ETC_D=/etc/awstats
AWSTATS_BIN_D=/usr/lib/cgi-bin
AWSTATS_TOOLS_D=/usr/share/awstats/tools
AWSTATS_DOC_D=/usr/share/awstats
OPENSSL_BIN=/usr/bin/openssl
LIB_SSL_PATH=/lib/libssl.so
LIB_CRYPTO_PATH=/lib/libcrypto.so
CLIENT_PHP_BIN=/opt/psa/bin/php-cli
SNI_SUPPORT=true
APS_DB_DRIVER_LIBRARY=/usr/lib/x86_64-linux-gnu/sw/libmysqlserver.so.2.0
SA_MAX_MAIL_SIZE=256000
}
# echo message to product log, also to console in debug mode
p_echo()
{
if [ -n "$product_log" ] ; then
echo "$@" >> "$product_log" 2>&1
fi
if [ -n "$PLESK_INSTALLER_DEBUG" -o -n "$PLESK_INSTALLER_VERBOSE" -o -z "$product_log" ] ; then
echo "$@" >&2
fi
}
# same as p_echo, but without new line
pnnl_echo()
{
p_echo -n "$@"
}
echo_try()
{
msg="$*"
pnnl_echo " Trying to $msg... "
}
suc()
{
p_echo "done"
}
get_default_locale()
{
# Note that CentOS 7 typically doesn't have C.UTF-8
for lc in "C.UTF-8" "en_US.UTF-8" "C"; do
if [ -z "`LC_ALL=$lc locale 2>&1 >/dev/null`" ]; then
echo "$lc"
return 0
fi
done
echo "C"
}
call_optional_function()
{
local type_output="`LC_ALL=C type \"$1\" 2>/dev/null | head -n 1`"
case "$type_output" in
*function)
"$@"
;;
*)
return 0
;;
esac
}
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
#
# Support for runtime patching of shell scripts (including utilities and package scripts).
#
# --- Service functions ---
# Load and apply a patch in a relatively safe way
rp_safe_load_patch()
{
local patch_file="$1"
echo_try "load shell patch '$patch_file'"
/bin/sh -n "$RP_BASEDIR/$patch_file" &&
{
. "$RP_BASEDIR/$patch_file"
RP_LOADED_PATCHES="$RP_LOADED_PATCHES $patch_file"
} &&
suc
}
# Apply patches specific to the current context (e.g., depending on utility basename or package name)
# This is currently not implemented. This may be overriden by "spark".
rp_patch_runtime_context_specific()
{
:
}
# --- Main entry points ---
rp_patch_runtime()
{
# List of loaded patch files
RP_LOADED_PATCHES=
local RP_BASEDIR="$PRODUCT_BOOTSTRAPPER_DIR/rp"
[ -d "$RP_BASEDIR" ] || return 0
if [ -r "$RP_BASEDIR/spark" ]; then
rp_safe_load_patch "spark"
fi
call_optional_function rp_patch_runtime_context_specific "$@"
}
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
# vim:ft=sh
initial_conf()
{
PRODNAME="psa"
PRODUCT_NAME="psa"
product=${PRODNAME}
PRODUCT_FULL_NAME="Plesk"
product_etc="/etc/${PRODNAME}"
prod_conf_t="/etc/psa/psa.conf"
support_contact="https://support.plesk.com/"
conceived_os_vendor=Ubuntu
conceived_os_version="24.04"
clients_group="psacln"
clients_GID="10001"
services_group="psaserv"
services_GID="10003"
product_suff="saved_by_${product}".`date "+%m.%d;%H:%M"`
product_suffo="saved_by_${product}"
# plesk default password
PRODUCT_DEFAULT_PASSWORD="setup"
}
read_conf()
{
[ -n "$prod_conf_t" ] || prod_conf_t=/etc/psa/psa.conf
if [ -s $prod_conf_t ]; then
tmp_var=`perl -e 'undef $/; $_=<>; s/#.*$//gm;
s/^\s*(\S+)\s*/$1=/mg;
print' $prod_conf_t`
eval $tmp_var
else
if ! is_product_installation; then
p_echo "Unable to find product configuration file: $prod_conf_t. Default values will be used."
return 1
fi
fi
return 0
}
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
# vim:ft=sh:
#set_params
set_common_params()
{
common_var=0
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
LANG="`get_default_locale`"
export PATH LANG
unset GREP_OPTIONS
umask 022
ulimit -n 65535 2>/dev/null
get_product_versions
certificate_file="$PRODUCT_ETC_D/httpsd.pem"
services="/etc/services"
crontab="/usr/bin/crontab"
SYSTEM_RC_D="/etc/init.d"
PLESK_LIBEXEC_DIR="/usr/lib/plesk-9.0"
PLESK_DB_DIR="/var/lib/plesk"
PRODUCT_BOOTSTRAPPER_DIR="`printf "/opt/psa/bootstrapper/pp%s-bootstrapper" "$product_this_version"`"
AUTOGENERATED_CONFIGS="#ATTENTION!\n#\n#DO NOT MODIFY THIS FILE BECAUSE IT WAS GENERATED AUTOMATICALLY,\n#SO ALL YOUR CHANGES WILL BE LOST THE NEXT TIME THE FILE IS GENERATED.\n"
AUTOGENERATED_CONFIGS_UPGRADE="#ATTENTION!\n#\n#DO NOT MODIFY THIS FILE BECAUSE IT WAS GENERATED AUTOMATICALLY,\n#SO ALL YOUR CHANGES WILL BE LOST AFTER YOU UPGRADE PLESK.\n"
PRODUCT_LOGS_D="/var/log/plesk"
sendmail="/usr/sbin/sendmail"
ps="ps axw"
ifconfig="/sbin/ifconfig -a"
machine="linux"
if [ -f /etc/debian_version ]; then
linux_distr="debian"
else
linux_distr="redhat"
fi
dummy_home="/"
if [ -x /usr/sbin/nologin ]; then
dummy_shell="/usr/sbin/nologin"
else
dummy_shell="/bin/false"
fi
rp_patch_runtime
}
get_product_versions()
{
# Don't use global variables set elsewhere in this code. Use substitutions if needed.
local prod_root_d="/opt/psa"
product_name="psa"
if [ -z "$product_this_version" ]; then
# 1. Try to fetch version from file created by bootstrapper (should be 3-component).
product_this_version="`cat "/var/lock/plesk-target-version" 2>/dev/null`"
# 2. Fallback to $PRODUCT_ROOT_D/version (should be 3-component).
if [ -z "$product_this_version" -a -r "$prod_root_d/version" ]; then
product_this_version="`awk '{ print $1 }' "$prod_root_d/version"`"
fi
# 3. Fallback to hardcoded version (2-component). This may cause some other code to fail.
if [ -z "$product_this_version" ]; then
product_this_version="18.0"
echo "Unable to determine \$product_this_version, will use less precise value '$product_this_version'" >&2
fi
fi
product_version="$product_this_version"
if [ -z "$product_prev_version" ]; then
if [ -r "$prod_root_d/version.upg" ]; then
product_prev_version=`awk '{ print $1 }' "$prod_root_d/version.upg"`
elif [ -r "$prod_root_d/version" ]; then
product_prev_version=`awk '{ print $1 }' "$prod_root_d/version"`
else
product_prev_version="$product_this_version"
fi
fi
}
# Clean installation of the product is being performed
is_product_installation()
{
[ "X$do_upgrade" != "X1" -a ! -s "/opt/psa/version.upg" ]
}
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
### This is a compatibility wrapper for legacy monolithic mailmng.
### Serves only to avoid breaking any third-party code. Plesk does not and
### must not use this utility.
###
### Since this is a compatibility wrapper, adding *new* commands to it is not
### necessarry and even bad, since this will slow down the transition.
# --- command and utility definitions ---
MAILMNG_CORE_COMMANDS="
--add-mailname
--remove-mailname
--rename-mailname
--add-mailbox
--remove-mailbox
--set-password
--add-alias
--remove-alias
--add-domain
--remove-domain
--rename-domain
--turn-on-domain
--turn-off-domain
--add-domain-alias
--del-domain-alias
--rename-domain-alias
--get-mailbox-size
--set-mailbox-disk-quota
--set-domain-disk-quota
"
MAILMNG_BLACK_WHITE_COMMANDS="
--add-badmailfrom
--remove-badmailfrom
--add-whitelist
--remove-whitelist
"
MAILMNG_DOMAIN_COMMANDS="
--set-bounce
--set-catchall
--set-reject
--unset-reject
--set-domain-key
--remove-domain-key
--add-domain-to-sender-transport
--remove-domain-from-sender-transport
--remove-sender-transport
"
MAILMNG_MAILNAME_COMMANDS="
--add-redirect
--remove-redirect
--set-autoresponder
--reset-autoresponder
--list-attachments
--add-attachment
--remove-attachment
"
MAILMNG_SERVER_COMMANDS="
--set-maps-protection
--update-spf
--features
--set-max-letter-size
--get-max-letter-size
--set-mail-params
--get-mailbox-size-limit
--add-recipient-address-mapper
"
MAILMNG_SERVICE_COMMANDS="
--start-service
--stop-service
--restart-service
--reload-service
--status-service
"
HELP_COMMANDS="
-h
--help
--help-commands
--help-legacy
--help-stdin
"
DROPPED_COMMANDS="
--add-blacklist --remove-blacklist
--add-handler --update-handler --remove-handler --disable-handler --enable-handler --check-handler
--without-restart
--start-smtpd --stop-smtpd --restart-smtpd --status-smtpd
--start-qmail-send --stop-qmail-send
--start-maild --stop-maild --restart-maild --status-maild
--start-milter --stop-milter --restart-milter --status-milter
"
UTILITIES="
mailmng-black-white
mailmng-core
mailmng-domain
mailmng-mailname
mailmng-server
mailmng-service
"
# --- initialization ---
product_log="/dev/stderr"
product_problems_log="$product_log"
problems_occured=0
bootstrapper_mode_file="/tmp/pp-bootstrapper-mode.flag"
product_default_conf
initial_conf
set_common_params
read_conf
command="$1"
# --- help ---
usage()
{
if [ -n "$*" ]; then
echo "ERROR: $*" >&2
echo >&2
fi
echo "Usage: mailmng <COMMAND> <COMMAND OPTIONS...>" >&2
echo >&2
echo "WARNING: you are using legacy mailmng compatibility wrapper." >&2
echo "Please use one of the following utilities instead in the future: `echo \"$UTILITIES\" | sed -e 's/^/ /'`" >&2
echo "This wrapper suppresses any supplied STDIN. If you're getting errors like" >&2
echo "'Failed to read and parse session mail data from STDIN.' then you should use one of the" >&2
echo "utilities mentioned above and supply valid STDIN. See also --help-stdin option." >&2
echo "Next time consider using Plesk CLI utilities or API instead of relying on its internals." >&2
exit 2
}
[ -n "$command" ] || usage
for cmd in $HELP_COMMANDS; do
if [ "$cmd" = "$command" ]; then
usage
fi
done
for cmd in $DROPPED_COMMANDS; do
if [ "$cmd" = "$command" ]; then
if [ -f "$bootstrapper_mode_file" ]; then
echo "Command '$0 $@' was skipped as it is not supported anymore." >&2
exit 0
else
usage "$command command is no longer supported. Please use other equivalents available among Plesk mail utilities."
fi
fi
done
# --- proxy call to appropriate utility ---
for utility in $UTILITIES; do
eval "commands=$`echo $utility | tr 'a-z-' 'A-Z_'`_COMMANDS"
for cmd in $commands; do
if [ "$cmd" = "$command" ]; then
exec "$PRODUCT_ROOT_D/admin/sbin/$utility" "$@" < /dev/null
fi
done
done
usage "Unknown command: $command"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -1,73 +0,0 @@
#!/bin/bash -e
# Free IP Geolocation by DB-IP: https://db-ip.com/db/download/ip-to-country-lite
VAR_D="/usr/local/psa/var/modules/firewall/geoip/`basename "$0"`.d"
die()
{
echo "`basename "$0"`: $*" >&2
exit 1
}
load_settings()
{
[ ! -s "$VAR_D/settings.sh" ] || . "$VAR_D/settings.sh"
}
save_settings()
{
cat > "./settings.sh" <<-EOT
: \${DOWNLOAD_TIMEOUT:=$DOWNLOAD_TIMEOUT}
EOT
}
exists()
{
[ -s "$VAR_D/db.sqlite3" ]
}
fetch()
{
load_settings
rm -rf "$VAR_D".*
mkdir -p "`dirname "$VAR_D"`"
local tgt_d=
tgt_d="`mktemp -d "$VAR_D.XXXXXX"`"
chmod 700 "$tgt_d"
cd "$tgt_d"
local url="https://download.db-ip.com/free/dbip-country-lite-`date -d 'now - 1 day' --utc +%Y-%m`.csv.gz"
date --utc --rfc-3339=seconds > updated-at
save_settings
curl ${DOWNLOAD_TIMEOUT:+-m "$DOWNLOAD_TIMEOUT"} -fsSL "$url" | gzip -cd > dbip.csv
sqlite3 db.sqlite3 <<-EOT
CREATE TABLE ips (ip_from TEXT, ip_to TEXT, country_iso_code TEXT);
CREATE INDEX ips_code ON ips (country_iso_code);
.mode csv
.import dbip.csv ips
EOT
[ "`sqlite3 db.sqlite3 'SELECT count(*) FROM ips;'`" -gt 0 ] || die "Downloaded DB is empty"
rm -f dbip.csv
rm -rf "$VAR_D"
mv -fT "$tgt_d" "$VAR_D"
}
list()
{
local country="$1"
[ -n "$country" ] || die "--list requires a single 2-letter ISO country code argument"
sqlite3 "$VAR_D/db.sqlite3" \
"SELECT ip_from || '-' || ip_to FROM ips WHERE country_iso_code = '$country';"
}
case "$1" in
--exists) exists ;;
--fetch) fetch ;;
--list) list "$2" ;;
*) die "Unknown command: '$1'" ;;
esac

View File

@@ -1,10 +0,0 @@
#!/bin/bash -e
# GeoIP2 data created by MaxMind: https://www.maxmind.com . Requires license key.
# Updated twice weekly, every Tuesday and Friday.
# Each account (license key) is limited to 2000 total direct downloads in a 24 hour period.
VAR_D="/usr/local/psa/var/modules/firewall/geoip/`basename "$0"`.d"
EDITION_TYPE="GeoIP2"
. "`dirname "$0"`/maxmind-lite"

View File

@@ -1,106 +0,0 @@
#!/bin/bash -e
# Free but less accurate GeoLite2 data created by MaxMind: https://www.maxmind.com . Requires license key.
# Updated twice weekly, every Tuesday and Friday.
# Each account (license key) is limited to 2000 total direct downloads in a 24 hour period.
: ${VAR_D:="/usr/local/psa/var/modules/firewall/geoip/`basename "$0"`.d"}
: ${EDITION_TYPE:="GeoLite2"}
EDITION_ID="$EDITION_TYPE-Country-CSV"
die()
{
echo "`basename "$0"`: $*" >&2
exit 1
}
load_settings()
{
[ ! -s "$VAR_D/settings.sh" ] || . "$VAR_D/settings.sh"
}
save_settings()
{
cat > "./settings.sh" <<-EOT
: \${DOWNLOAD_TIMEOUT:=$DOWNLOAD_TIMEOUT}
: \${LICENSE_KEY:=$LICENSE_KEY}
EOT
}
exists()
{
[ -s "$VAR_D/db.sqlite3" ]
}
fetch()
{
load_settings
[ "$EDITION_TYPE" = "GeoLite2" -o "$EDITION_TYPE" = "GeoIP2" ] ||
die "Unsupported MaxMind EDITION_TYPE='$EDITION_TYPE'"
[ -n "$LICENSE_KEY" ] ||
die "Missing MaxMind LICENSE_KEY"
rm -rf "$VAR_D".*
mkdir -p "`dirname "$VAR_D"`"
local tgt_d=
tgt_d="`mktemp -d "$VAR_D.XXXXXX"`"
chmod 700 "$tgt_d"
cd "$tgt_d"
# Database structure: https://dev.maxmind.com/geoip/docs/databases/city-and-country
local url="https://download.maxmind.com/app/geoip_download?edition_id=$EDITION_ID&license_key=$LICENSE_KEY&suffix=zip"
date --utc --rfc-3339=seconds > updated-at
save_settings
curl ${DOWNLOAD_TIMEOUT:+-m "$DOWNLOAD_TIMEOUT"} -fsSL "$url" -o dbip-csv.zip
unzip -jq dbip-csv.zip
sqlite3 db.sqlite3 <<-EOT
-- CentOS 7 has SQLite 3.7.17, which doesn't auto-create tables based on CSV header
CREATE TABLE blocks_ipv4 (network TEXT, geoname_id TEXT, registered_country_geoname_id TEXT,
represented_country_geoname_id TEXT, is_anonymous_proxy TEXT, is_satellite_provider TEXT);
CREATE TABLE blocks_ipv6 (network TEXT, geoname_id TEXT, registered_country_geoname_id TEXT,
represented_country_geoname_id TEXT, is_anonymous_proxy TEXT, is_satellite_provider TEXT);
CREATE TABLE locations_en(geoname_id TEXT, locale_code TEXT, continent_code TEXT,
continent_name TEXT, country_iso_code TEXT, country_name TEXT, is_in_european_union TEXT);
CREATE INDEX blocks_ipv4_geoname_id ON blocks_ipv4 (geoname_id);
CREATE INDEX blocks_ipv6_geoname_id ON blocks_ipv6 (geoname_id);
CREATE INDEX locations_en_code_geoname_id ON locations_en (country_iso_code, geoname_id);
.mode csv
.import $EDITION_TYPE-Country-Blocks-IPv4.csv blocks_ipv4
.import $EDITION_TYPE-Country-Blocks-IPv6.csv blocks_ipv6
.import $EDITION_TYPE-Country-Locations-en.csv locations_en
-- Since the tables already existed on import, header is also imported as data, remove it
DELETE FROM blocks_ipv4 WHERE geoname_id = 'geoname_id';
DELETE FROM blocks_ipv6 WHERE geoname_id = 'geoname_id';
DELETE FROM locations_en WHERE geoname_id = 'geoname_id';
EOT
for table in blocks_ipv4 blocks_ipv6 locations_en; do
[ "`sqlite3 db.sqlite3 "SELECT count(*) FROM $table;"`" -gt 0 ] ||
die "Table '$table' in the downloaded DB is empty"
done
rm -f dbip-csv.zip *.csv
rm -rf "$VAR_D"
mv -fT "$tgt_d" "$VAR_D"
}
list()
{
local country="$1"
[ -n "$country" ] || die "--list requires a single 2-letter ISO country code argument"
sqlite3 "$VAR_D/db.sqlite3" "
SELECT network FROM blocks_ipv4 b INNER JOIN locations_en l ON b.geoname_id = l.geoname_id
WHERE l.country_iso_code = '$country';
SELECT network FROM blocks_ipv6 b INNER JOIN locations_en l ON b.geoname_id = l.geoname_id
WHERE l.country_iso_code = '$country';
"
}
case "$1" in
--exists) exists ;;
--fetch) fetch ;;
--list) list "$2" ;;
*) die "Unknown command: '$1'" ;;
esac

View File

@@ -1,357 +0,0 @@
#!/usr/local/psa/bin/py3-python -IS
""" ipset management for country filtering in firewall. """
import argparse
import ipaddress
import json
import logging
import os
import subprocess
import sys
import textwrap
log = logging.getLogger('ipsets')
SBIN_D = os.path.dirname(os.path.abspath(__file__))
VAR_D = "/usr/local/psa/var/modules/firewall"
DATA_SOURCE_BIN_D = os.path.join(SBIN_D, 'geoip')
DATA_SOURCE_VAR_D = os.path.join(VAR_D, 'geoip')
SETTINGS_PATH = os.path.join(DATA_SOURCE_VAR_D, 'settings.json')
IPSET_PREFIX = "plesk-ip"
def set_up_logging(verbosity):
""" Set up logging based on --verbose count and PLESK_DEBUG environment. """
verbosity = verbosity or 0
level = {
0: logging.CRITICAL,
1: logging.ERROR,
2: logging.WARNING,
3: logging.INFO,
4: logging.DEBUG,
}.get(verbosity, logging.CRITICAL)
if verbosity >= 4 or os.getenv('PLESK_DEBUG'):
level = logging.DEBUG
logging.basicConfig(level=level, format='[%(asctime)s] %(levelname)8s %(message)s')
def parse_args():
epilog = f"""\
environment variables:
DOWNLOAD_TIMEOUT Data source download timeout, seconds
LICENSE_KEY Data source license key (e.g. for 'maxmind')
PLESK_DEBUG Set logging verbosity to maximum
data source contract:
Each --data-source value is an executable script with the following commands:
--exists Returns 0 only when the GeoIP data exists locally
(i.e. previous --fetch was successful).
--fetch Fetches GeoIP data from a remote source, preprocesses it,
and stores it locally. May use and store additional
environment variables, such as LICENSE_KEY. Such variables
may be absent on subsequent calls. Store data under
{DATA_SOURCE_VAR_D}/$data_source.d .
Avoid clobbering data on upstream errors.
--list ZZ Prints IP ranges or CIDR networks for both IPv4 and IPv6,
which are mapped to the country code ZZ, each on a separate
line. Order does not matter. Should use only local data,
but may use remote data (not recommended). Output examples:
127.0.0.0/8
192.0.0.0-192.0.0.255
fe80::/10
2001:db8::-2001:db8:ffff:ffff:ffff:ffff:ffff:ffff
"""
parser = argparse.ArgumentParser(description="Manage ipsets for country filtering in the firewall",
epilog=textwrap.dedent(epilog),
formatter_class=argparse.RawDescriptionHelpFormatter)
commands = parser.add_mutually_exclusive_group(required=True)
commands.add_argument('--configure', action='store_true',
help="Set up country ipsets. Create local GeoIP DB if missing, "
"persist settings, recreate country ipsets.")
commands.add_argument('--update', action='store_true',
help="Update local GeoIP DB from a remote source, then recreate all "
"country ipsets. Use from a cron job.")
commands.add_argument('--recreate', action='store_true',
help="Create missing and remove unused country ipsets. "
"Use from a firewall script.")
parser.add_argument('-v', '--verbose', action='count', default=0,
help="Increase logging verbosity, can be specified multiple times.")
parser.add_argument('-f', '--force', action='store_true',
help="Recreate all country ipsets instead of only missing and extra ones. "
"With --configure will also recreate local GeoIP DB and "
"update its settings.")
parser.add_argument('-d', '--data-source', metavar='NAME', required=True, type=type_data_source,
help="Data source name. Each data source is a script under "
f"{DATA_SOURCE_BIN_D} or {DATA_SOURCE_VAR_D}, e.g. 'maxmind'.")
parser.add_argument('-c', '--countries', nargs='*', metavar='ZZ', type=type_country_code,
help="List of 2-letter ISO 3166 country codes.")
args = parser.parse_args()
return args
def type_data_source(data_source):
""" Type caster and checker for --data-source. """
for data_source_d in (DATA_SOURCE_BIN_D, DATA_SOURCE_VAR_D):
path = os.path.join(data_source_d, data_source)
if os.access(path, os.X_OK):
return path
raise argparse.ArgumentTypeError(f"Unsupported data source: {data_source!r}")
def type_country_code(code):
""" Type caster and checker for --countries. """
if len(code) == 2 and code.isalpha() and code.isupper():
return code
raise argparse.ArgumentTypeError(f"Not a 2-letter ISO 3166 country code: {code!r}")
def log_geoip_data_dir(data_source):
""" Just logs expected data source local storage directory (by convention). """
data_source = os.path.basename(data_source)
log.debug("Data directory for %r data source is expected to be %r",
data_source, os.path.join(DATA_SOURCE_VAR_D, data_source + ".d"))
def has_geoip_data(data_source):
""" Returns True if GeoIP data is already fetched. """
log.debug("Checking for GeoIP data existence via %r", data_source)
return subprocess.call([data_source, '--exists']) == 0
def fetch_geoip_data(data_source):
""" Refetches GeoIP data from a remote source. """
log.info("Fetching GeoIP data via %r", data_source)
subprocess.check_call([data_source, '--fetch'])
def list_geoip_data(data_source, country_code):
""" Lists GeoIP data for the country_code (assuming it is fetched).
Data is a list of IP ranges or CIDR networks for both IPv4 and IPv6.
"""
log.debug("Listing GeoIP data for %r via %r", country_code, data_source)
data = subprocess.check_output([data_source, '--list', country_code], universal_newlines=True)
return data.split()
def geoip_data_to_networks(entries):
""" Generator of IPv4Network and IPv6Network objects from a list of ranges or networks.
>>> list(geoip_data_to_networks(['10.0.0.0/24', 'fe80::/10']))
[IPv4Network('10.0.0.0/24'), IPv6Network('fe80::/10')]
>>> list(geoip_data_to_networks(['10.0.0.0-10.0.0.19', '::-::3']))
[IPv4Network('10.0.0.0/28'), IPv4Network('10.0.0.16/30'), IPv6Network('::/126')]
>>> list(geoip_data_to_networks(['127.0.0.1', '::1']))
[IPv4Network('127.0.0.1/32'), IPv6Network('::1/128')]
>>> list(geoip_data_to_networks(['invalid']))
Traceback (most recent call last):
...
ValueError: 'invalid' does not appear to be an IPv4 or IPv6 network
>>> list(geoip_data_to_networks(['from-to']))
Traceback (most recent call last):
...
ValueError: 'from' does not appear to be an IPv4 or IPv6 address
"""
for entry in entries:
if '-' in entry:
str_from, str_to = entry.split('-', maxsplit=1)
ip_from, ip_to = ipaddress.ip_address(str_from), ipaddress.ip_address(str_to)
yield from ipaddress.summarize_address_range(ip_from, ip_to)
else:
yield ipaddress.ip_network(entry)
def list_existing_ipset_names():
""" Lists ipsets from the system. """
log.debug("Listing existing ipset names from system")
ipsets = subprocess.check_output(["ipset", "list", "-name"], universal_newlines=True).split()
log.debug("Got ipset names: %r", ipsets)
return ipsets
def round_to_power_of_2(x):
""" Returns value rounded to the next nearest non-negative power of 2.
>>> round_to_power_of_2(0)
1
>>> round_to_power_of_2(1)
1
>>> round_to_power_of_2(32)
32
>>> round_to_power_of_2(1000)
1024
"""
return 2 ** (x - 1).bit_length() if x >= 1 else 1
def create_ipset(ipset_name, ip_version, num_elements=0):
""" Creates ipset ipset_name for ip_version with num_elements estimate. """
# Account for possible growth due to updates, use a value that will not change often
num_elements = round_to_power_of_2(int(num_elements * 1.5))
maxelem_args = ["maxelem", str(num_elements)] if num_elements > 65536 else []
family_args = ["family", "inet" if str(ip_version) != '6' else "inet6"]
cmd = ["ipset", "create", ipset_name, "hash:net", "-exist"] + family_args + maxelem_args
try:
log.debug("Creating %r ipset: %r", ipset_name, cmd)
subprocess.check_call(cmd)
except Exception as ex:
log.warning("Failed to create %r ipset from the first try, possibly 'maxelem' changed, "
"will try recreating: %s",
ipset_name, ex)
try:
destroy_ipset(ipset_name)
except Exception as ex:
log.debug("Destroying %r ipset failed, likely due to existing references", ipset_name)
raise RuntimeError(f"Cannot recreate ipset {ipset_name!r}: {ex} "
"Try stopping the plesk-firewall.service first.") from ex
log.debug("Creating new %r ipset: %r", ipset_name, cmd)
subprocess.check_call(cmd)
def destroy_ipset(ipset_name):
""" Destroys ipset_name. This will fail if it is referenced by any iptables rules. """
log.debug("Destroying %r ipset", ipset_name)
subprocess.check_call(["ipset", "destroy", ipset_name])
def update_ipset(ipset_name, networks):
""" Replaces networks in ipset_name. """
stdin = "\n".join([f"flush {ipset_name}"] + [f"add {ipset_name} {net}" for net in networks])
log.debug("Updating %r ipset networks, %d entries", ipset_name, len(networks))
subprocess.run(["ipset", "restore"], check=True, universal_newlines=True, input=stdin)
def ipset_name(country_code, ip_version):
""" Returns ipset name for the country_code and ip_version (4 or 6). """
return IPSET_PREFIX + str(ip_version) + "-" + country_code
def recreate_ipsets(data_source, countries, recreate_all=False):
""" Recreates ipsets for the countries, using data_source.
By default, only missing ipsets are created and unused are removed.
If recreate_all, all ipsets are recreated.
"""
existing_ipsets = set(list_existing_ipset_names())
log.debug("Checking for missing ipsets (recreate_all=%r)", recreate_all)
required_ipsets = set()
for country_code in countries:
v4_name, v6_name = ipset_name(country_code, 4), ipset_name(country_code, 6)
required_ipsets.add(v4_name)
required_ipsets.add(v6_name)
if not recreate_all and v4_name in existing_ipsets and v6_name in existing_ipsets:
log.debug("Skip recreating already existing ipsets for %r country: %r, %r",
country_code, v4_name, v6_name)
continue
log.info("Creating and populating ipsets for %r country: %r, %r",
country_code, v4_name, v6_name)
v4_nets, v6_nets = [], []
for net in geoip_data_to_networks(list_geoip_data(data_source, country_code)):
if net.version == 4:
v4_nets.append(net)
elif net.version == 6:
v6_nets.append(net)
else:
raise RuntimeError(f"Network {net} is neither IPv4 nor IPv6")
create_ipset(v4_name, 4, len(v4_nets))
create_ipset(v6_name, 6, len(v6_nets))
update_ipset(v4_name, v4_nets)
update_ipset(v6_name, v6_nets)
log.debug("Checking for unused ipsets")
for name in existing_ipsets:
try:
if name.startswith(IPSET_PREFIX) and name not in required_ipsets:
log.info("Destroying unused ipset: %r", name)
destroy_ipset(name)
except Exception as ex:
log.warning("Cannot remove ipset %r, will try next time: %s", name, ex)
def store_settings(countries):
""" Stores settings for subsequent calls. """
log.debug("Storing settings into %r", SETTINGS_PATH)
data = {
'countries': sorted(countries),
}
os.makedirs(os.path.dirname(SETTINGS_PATH), 0o755, exist_ok=True)
with open(SETTINGS_PATH, 'w') as fd:
json.dump(data, fd)
fd.write("\n")
def fetch_settings():
""" Fetches previously stored settings. """
log.debug("Fetching settings from %r", SETTINGS_PATH)
try:
with open(SETTINGS_PATH, 'r') as fd:
data = json.load(fd)
log.debug("Fetched settings: %r", data)
return data['countries']
except Exception as ex:
raise RuntimeError(f"Cannot read persisted settings from {SETTINGS_PATH!r}: {ex}") from ex
def configure(data_source, countries, recreate_all=False):
""" Sets up countries ipsets from the data_source. Stores settings (countries, for data source). """
if recreate_all or not has_geoip_data(data_source):
fetch_geoip_data(data_source)
countries = countries or []
store_settings(countries)
recreate_ipsets(data_source, countries, recreate_all)
def update(data_source, countries):
""" Updates data from the data_source, then updates countries ipsets. """
fetch_geoip_data(data_source)
if countries is None:
countries = fetch_settings()
recreate_ipsets(data_source, countries, recreate_all=True)
def recreate(data_source, countries, recreate_all=False):
""" Recreates missing countries ipsets and removes unused ones, uses data from the data_source. """
if countries is None:
countries = fetch_settings()
recreate_ipsets(data_source, countries, recreate_all)
def main():
args = parse_args()
set_up_logging(args.verbose)
log.debug("Options: %s", args)
log_geoip_data_dir(args.data_source)
if args.configure:
configure(args.data_source, args.countries, args.force)
elif args.update:
update(args.data_source, args.countries)
elif args.recreate:
recreate(args.data_source, args.countries, args.force)
if __name__ == '__main__':
try:
main()
except Exception as ex:
print(f"{ex}", file=sys.stderr)
log.error("%s", ex)
log.debug("This exception happened at:", exc_info=sys.exc_info())
sys.exit(1)
# vim: ft=python

View File

@@ -1,445 +0,0 @@
#!/usr/local/psa/bin/py3-python -IS
""" Safe firewall rules activation and feature checks. This is a 'safeact' replacement. """
import argparse
import atexit
import errno
import logging
import os
import select
import shutil
import signal
import stat
import subprocess
import sys
import textwrap
import time
from datetime import datetime
log = logging.getLogger('rules')
PLESKRC_BIN = "/usr/local/psa/admin/sbin/pleskrc"
VAR_D = "/usr/local/psa/var/modules/firewall"
""" extension var directory """
SCRIPT_NEW = os.path.join(VAR_D, "firewall-new.sh")
""" new set of firewall rules """
SCRIPT_ACTIVE = os.path.join(VAR_D, "firewall-active.sh")
""" previous (active) set of firewall rules """
SCRIPT_EMERGENCY = os.path.join(VAR_D, "firewall-emergency.sh")
""" emergency set of firewall rules - ones that disable firewall """
PIPE_PATH = os.path.join(VAR_D, "confirm.pipe")
""" interprocess communication named pipe (fifo) """
ROLLBACK_FLAG = os.path.join(VAR_D, "rollback.flag")
""" "new firewall rules turned out to be bad" flag """
DEFAULT_CONFIRM_INTERVAL = 15
""" default confirmation timeout, in seconds """
MINIMAL_CONFIRM_INTERVAL = 5
""" minimal time the code will actually await confirmation token, in seconds """
MINIMAL_SCRIPT_TIMEOUT = 5
""" minimal time the code will allow a subprocess to execute, in seconds """
class ConfirmFailed(RuntimeError):
pass
def set_up_logging(verbosity):
""" Set up logging based on --verbose count and PLESK_DEBUG environment. """
verbosity = verbosity or 0
level = {
0: logging.CRITICAL,
1: logging.ERROR,
2: logging.WARNING,
3: logging.INFO,
4: logging.DEBUG,
}.get(verbosity, logging.CRITICAL)
if verbosity >= 4 or os.getenv('PLESK_DEBUG'):
level = logging.DEBUG
logging.basicConfig(level=level, format='[%(asctime)s] %(levelname)8s %(message)s')
def parse_args():
epilog = f"""\
environment variables:
PHP_SAFEACT_TOKEN Activation token
PHP_SAFEACT_CONFIRM_INTERVAL Confirmation timeout (default: {DEFAULT_CONFIRM_INTERVAL})
(activation and rollback each take at most this time,
but system will actually wait for confirmation token
for at least {MINIMAL_CONFIRM_INTERVAL} seconds, which may
increase the effective timeout, which may be
additionally increased due to misbehaving child
processes by up to {3 * MINIMAL_SCRIPT_TIMEOUT} seconds)
PLESK_DEBUG Set logging verbosity to maximum
"""
parser = argparse.ArgumentParser(description="Activate firewall rules or check its features safely",
epilog=textwrap.dedent(epilog),
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('-v', '--verbose', action='count', default=0,
help="Increase logging verbosity, can be specified multiple times.")
commands = parser.add_mutually_exclusive_group(required=True)
commands.add_argument('--activate', action='store_true',
help="Activate new rules. Synchronous.")
commands.add_argument('--confirm', action='store_true',
help="Commit activation of the new rules. Should be invoked from a new "
"SSH session or web/app server worker process to ensure an existing "
"network connection is not re-used.")
commands.add_argument('--try-enable-features', action='store_true',
help="Probe iptables features support. This will both check and "
"try to enable the specified features.")
act_opts = parser.add_argument_group("--activate arguments")
act_opts.add_argument('--rules-file', type=argparse.FileType('r'), default='-', metavar='PATH',
help="New rules script (default: %(default)s, i.e. STDIN)")
cfm_opts = parser.add_argument_group("--confirm arguments")
cfm_opts.add_argument('--wait', action='store_true',
help="Wait for the activation process to appear")
try_opts = parser.add_argument_group("--try-enable-features arguments")
try_opts.add_argument('--iptables', default='/usr/sbin/iptables',
help="iptables binary path (default: %(default)s)")
try_opts.add_argument('--table', default='filter',
help="iptables table name (default: %(default)s)")
try_opts.add_argument('--rule', default='-L',
help="iptables rule options (default: %(default)s), "
"use the default to check table and/or binary availability")
args = parser.parse_args()
return args
def get_token():
""" Returns activation token string. """
token = os.getenv('PHP_SAFEACT_TOKEN', '').strip()
if not token:
raise RuntimeError("Activation token is absent")
# Writes to pipes are atomic only up to certain system-specific limit (at least 512)
if len(token) >= select.PIPE_BUF - 1:
raise RuntimeError(f"Activation token is too long: {len(token)} characters")
return token
def get_confirm_timeout():
""" Returns confirmation timeout as int. """
timeout = os.getenv('PHP_SAFEACT_CONFIRM_INTERVAL')
if not timeout:
return DEFAULT_CONFIRM_INTERVAL
else:
value = int(timeout)
if value <= 0:
raise ValueError(f"Confirmation timeout is too small: {value}")
return value
def rm_f(path):
""" Equivalent of 'rm -f' for a file path. """
try:
log.debug("rm -f %r", path)
os.unlink(path)
except OSError as ex:
if ex.errno != errno.ENOENT:
raise
def verify_script_perms(path):
""" Checks that script file looks to be OK. """
log.debug("Checking %r script attributes", path)
st = os.lstat(path)
if not stat.S_ISREG(st.st_mode):
raise ValueError(f"{path}: The script is not a regular file")
if st.st_size == 0:
raise ValueError(f"{path}: The script is empty")
if st.st_uid != 0:
raise ValueError(f"{path}: The script is not owned by root")
if st.st_mode != (stat.S_IFREG | 0o700):
raise ValueError(f"{path}: The script has permissions other than 0700")
def try_restart_service(service, timeout):
""" Restarts the service if it is already running. """
timeout = max(timeout, MINIMAL_SCRIPT_TIMEOUT)
log.debug("Trying to restart %r service with timeout=%s", service, timeout)
subprocess.check_call([PLESKRC_BIN, service, 'try-restart'], timeout=timeout)
def is_service_running(service):
""" Returns whether the given service is running. """
log.debug("Checking %r service status", service)
result = subprocess.run([PLESKRC_BIN, service, 'status'])
return result.returncode == 0
def execute_rules_script(script, timeout):
""" Executes script within a given timeout. """
timeout = max(timeout, MINIMAL_SCRIPT_TIMEOUT)
env = {k: v for k, v in os.environ.items() if k not in ('PHP_SAFEACT_TOKEN',)}
log.debug("Executing script %r with timeout=%s", script, timeout)
subprocess.check_call([script], timeout=timeout, env=env)
def apply_rules(script, cutoff_timestamp, confirm=True):
""" Applies rules script and (optionally) waits for confirmation until cutoff_timestamp.
On success links the script into active configuration.
"""
log.info("Trying to apply rules from %r until %s, %s confirmation",
script, datetime.fromtimestamp(cutoff_timestamp), "with" if confirm else "without")
execute_rules_script(script, cutoff_timestamp - time.time())
if confirm:
# This is required to ensure that there are no outstanding connections to browser
# and any new connections are allowed by firewall.
try:
try_restart_service('sw-cp-server', cutoff_timestamp - time.time())
if is_service_running('nginx'):
log.debug("Nginx looks to be the frontend web server")
try_restart_service('nginx', cutoff_timestamp - time.time())
else:
log.debug("Apache looks to be the frontend web server")
try_restart_service('apache', cutoff_timestamp - time.time())
except subprocess.TimeoutExpired as ex:
log.warning(f"{ex}. Will attempt to wait for confirmation anyway.")
log.debug("This exception happened at:", exc_info=sys.exc_info())
expected_token = get_token()
cutoff_timestamp = max(cutoff_timestamp, time.time() + MINIMAL_CONFIRM_INTERVAL)
log.debug("Waiting for a matching activation token on %r until %s",
PIPE_PATH, datetime.fromtimestamp(cutoff_timestamp))
# Open w/o blocking to ensure open doesn't block w/o writers present
with os.fdopen(os.open(PIPE_PATH, os.O_RDONLY | os.O_NONBLOCK), 'r') as pipe:
# Also keep the pipe open for writing, otherwise after the first read select()
# will immediately return with only EOF available to read
# (this normally indicates absence or writers).
with open(PIPE_PATH, 'wb'):
timeout = cutoff_timestamp - time.time()
while timeout > 0 and select.select([pipe], [], [], timeout)[0]:
token = pipe.readline().strip()
if token == expected_token:
log.info("Received matching activation token")
break
log.debug("Received non-matching activation token: %r", token)
timeout = cutoff_timestamp - time.time()
else:
raise ConfirmFailed("Did not receive a matching activation token "
"before confirmation timeout")
if script != SCRIPT_ACTIVE:
log.debug("Setting %r as the active configuration %r", script, SCRIPT_ACTIVE)
# Previously files were hardlinked, but we don't really need strict atomicity here
# and hardlinks may cause issues if somebody decides to meddle with the files manually
# (e.g. emergency may be hardlinked into active and may be updated due to copy into active)
rm_f(SCRIPT_ACTIVE)
log.debug("cp -Pa %r %r", script, SCRIPT_ACTIVE)
shutil.copy2(script, SCRIPT_ACTIVE, follow_symlinks=False)
else:
log.debug("Rules from %r are already the active configuration", script)
def try_create_pipe(path, stale_timestamp):
""" Creates a pipe if it doesn't exist, removes it if it is too old. Otherwise returns False. """
try:
ctime = os.path.getctime(path)
if ctime < stale_timestamp:
log.info("Removing stale named pipe %r created at %s", path, datetime.fromtimestamp(ctime))
os.unlink(path)
else:
return False
except OSError as ex:
if ex.errno != errno.ENOENT:
raise
log.debug("Creating named pipe %r and setting up atexit handler", path)
os.mkfifo(path, 0o600)
@atexit.register
def remove_pipe():
log.debug("Removing named pipe %r on exit", path)
rm_f(path)
return True
def rollback():
""" Rolls back to some working configuration. """
log.info("Rolling back to working configuration")
log.debug("touch %r", ROLLBACK_FLAG)
with open(ROLLBACK_FLAG, 'wb'):
pass
try:
try:
log.info("Trying to roll back from new to active configuration")
cutoff_timestamp = time.time() + get_confirm_timeout()
apply_rules(SCRIPT_ACTIVE, cutoff_timestamp)
except ConfirmFailed as ex:
raise ConfirmFailed(
"Connectivity failure occurred with both the new and rollback (previous) firewall configurations, "
"indicating that both configurations are faulty.") from ex
except Exception as ex:
log.info("Trying to roll back from active to emergency configuration")
apply_rules(SCRIPT_EMERGENCY, 0, confirm=False)
raise ConfirmFailed(f"{ex} "
"As an emergency measure, "
"the firewall was disabled and a configuration without firewall rules was applied. "
"To resolve the issue, correct the firewall rules and re-enable the firewall.")
def activate(rules_file):
""" Activates new rules supplied via rules_file. """
rm_f(ROLLBACK_FLAG)
timeout = get_confirm_timeout()
start_timestamp = time.time()
cutoff_timestamp = start_timestamp + timeout
# Assume other activations use the same timeout
stale_timestamp = start_timestamp - 2.1 * timeout
log.info("Activating with token=%r, timeout=%s", get_token(), timeout)
log.debug("Setting up signal handlers to ensure cleanup")
for signum in (signal.SIGTERM, signal.SIGHUP, signal.SIGQUIT):
signal.signal(signum, signal.getsignal(signal.SIGINT))
log.debug("Trying to create named pipe %r, until %s, file older than %s is considered stale",
PIPE_PATH,
datetime.fromtimestamp(cutoff_timestamp),
datetime.fromtimestamp(stale_timestamp))
while time.time() < cutoff_timestamp:
if try_create_pipe(PIPE_PATH, stale_timestamp):
log.debug("Pipe created")
break
time.sleep(0.5)
else:
log.debug("Could not create pipe")
raise RuntimeError("Previous rules activation didn't finish before confirmation timeout")
log.info("Writing new rules from %r into %r", rules_file.name, SCRIPT_NEW)
rm_f(SCRIPT_NEW)
log.debug("cat > %r", SCRIPT_NEW)
with os.fdopen(os.open(SCRIPT_NEW, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o700), 'w') as script_new:
shutil.copyfileobj(rules_file, script_new)
verify_script_perms(SCRIPT_ACTIVE)
try:
log.info("Trying to apply new configuration")
apply_rules(SCRIPT_NEW, cutoff_timestamp)
rm_f(SCRIPT_NEW)
except Exception:
rollback()
raise
def confirm(wait=False):
""" Confirms rules activation (new ones or during rollback). """
token = get_token()
if wait:
timeout = max(get_confirm_timeout(), MINIMAL_CONFIRM_INTERVAL)
cutoff_timestamp = time.time() + 2 * (timeout + 3 * MINIMAL_SCRIPT_TIMEOUT)
else:
cutoff_timestamp = time.time()
log.info("Confirming with token=%r until %s", token, datetime.fromtimestamp(cutoff_timestamp))
while True:
try:
# Open w/o creating the pipe/file if it doesn't exist ([Errno 2] No such file or directory)
# Open w/o blocking if no readers are present ([Errno 6] No such device or address)
with os.fdopen(os.open(PIPE_PATH, os.O_WRONLY | os.O_APPEND | os.O_NONBLOCK), 'w') as pipe:
log.debug("Writing activation token to %r", PIPE_PATH)
pipe.write(token + "\n")
break
except Exception as ex:
if time.time() >= cutoff_timestamp:
raise ConfirmFailed("Too late to confirm: no rules activation process") from ex
log.debug(f"No activation process yet, continue to wait: {ex}")
time.sleep(0.5)
if os.path.lexists(ROLLBACK_FLAG):
raise ConfirmFailed("Too late to confirm: new rules were rolled back")
def try_enable_features(iptables, table, rule):
"""
Checks if desired iptables features are enabled. Tries to enable them if not.
On modern systems iptables is capable of dynamically loading required kernel
modules. This is convenient, misleading and maybe even dangerous at the same time
( http://backstage.soundcloud.com/2012/08/shoot-yourself-in-the-foot-with-iptables-and-kmod-auto-loading/ ).
Since we don't want to meddle with kernel modules for obvious reasons, we use
iptables itself to check features support. As a side effect such checks may trigger
kernel module loading. Checks are isolated in a separate temporary chain, that
nobody refers to.
This approach has an added advantage of checking whether real iptables rules would
work, not some "support" per se. Practice shows that the latter may be misleading
and result in bugs. Therefore if you're not sure <rule> works on a given system,
just call this command with the given <rule>.
<rule> is <rule-specification> in terms of iptables(8). Specifying <target> as part
of it is not required and not particularly useful. <rule> can also be '-L' to check
table and/or binary availability.
"""
if rule == '-L':
# listing is "safe"
log.info("Checking feature: iptables=%r, table=%r, rule=%r", iptables, table, rule)
subprocess.check_call([iptables, '-t', table, rule, '-n'])
else:
# everything else is isolated in a temporary chain
chain = "plesk-fw-tmp-chain"
log.info("Checking feature: iptables=%r, table=%r, rule=%r, chain=%r",
iptables, table, rule, chain)
def remove_chain():
subprocess.check_call([iptables, '-t', table, '-F', chain])
subprocess.check_call([iptables, '-t', table, '-Z', chain])
subprocess.check_call([iptables, '-t', table, '-X', chain])
def create_chain():
subprocess.check_call([iptables, '-t', table, '-N', chain])
def append_rule(rule_args):
subprocess.check_call([iptables, '-t', table, '-A', chain] + rule_args)
try:
remove_chain()
except Exception as ex:
# Failure is OK here - it means chain didn't exist
log.debug("During initial %r chain removal: %s", chain, ex)
create_chain()
append_rule(rule.split())
remove_chain()
def main():
args = parse_args()
set_up_logging(args.verbose)
log.debug("Options: %s", args)
if args.activate:
activate(args.rules_file)
elif args.confirm:
confirm(args.wait)
elif args.try_enable_features:
try_enable_features(args.iptables, args.table, args.rule)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
log.debug("Interrupted:", exc_info=sys.exc_info())
sys.exit(2)
except Exception as ex:
print(f"{ex}")
log.error("%s", ex)
log.debug("This exception happened at:", exc_info=sys.exc_info())
sys.exit(1)
# vim: ft=python

View File

@@ -1,48 +0,0 @@
#!/bin/bash
# Copyright 1999-2023. Plesk International GmbH. All rights reserved.
PN=$(basename $0)
die ()
{
echo "$@" 1>&2;
exit 1
}
usage()
{
cat << EOT
Usage: $PN <user> <working-dir> [<gitarg1> <gitarg2>...]
Execute git command with user rights in selected working directory
EOT
}
if [ "$#" -le 3 ]; then
usage
exit 1
fi
username="$1"
if ! id "$username" >/dev/null 2>&1; then
die "Unknown user $username"
fi
shift
workdir="$1"
shift
git_cmd=$(command -v git)
if [ "$?" != "0" ]; then
die "Command git does not found"
fi
export PATH="/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin"
export GIT_SSH="/usr/local/psa/admin/sbin/modules/git/git_ssh"
export GIT_SSH_VARIANT=ssh
export PRESERVE_ENV="GIT_SSH,GIT_ASKPASS,GIT_PASS"
HOME=$(eval echo ~"$username")
export HOME
umask 022
/usr/local/psa/admin/sbin/filemng "$username" exec "$workdir" "$git_cmd" "$@"

View File

@@ -1,73 +0,0 @@
#!/bin/bash
# Copyright 1999-2016. Parallels IP Holdings GmbH. All Rights Reserved.
usage()
{
echo "Usage: $0 [-p <port>] <hostname> [<args>...]" >&2
exit 2
}
update_known_hosts()
{
local port= server= offset=0
if [ "$1" = "-o" ]; then
offset=2
fi
option_arg_num=$((offset+1))
if [ "${!option_arg_num}" = "-p" ]; then
port_offset=$((offset+2))
server_offset=$((offset+3))
port="${!port_offset}"
server="${!server_offset}"
else
server_offset=$((offset+1))
server="${!server_offset}"
fi
local hostname="`echo "$server" | cut -d@ -f2`"
local server_addr="$hostname${port:+:$port}"
KNOWN_HOSTS="`readlink -m ~/.ssh/git_known_hosts${port:+_with_port_$port}`"
if [ -f "$KNOWN_HOSTS" ] && [ -n "`ssh-keygen -F "$hostname" -f "$KNOWN_HOSTS"`" ]; then
echo "Public key for the server at '$server_addr' is already known in '$KNOWN_HOSTS'." >&2
return 0
fi
echo "Server at '$server_addr' is seen for the first time." >&2
echo "Adding its public key to the list of known hosts in '$KNOWN_HOSTS'." >&2
local key="`ssh-keyscan ${port:+-p $port} -H "$hostname"`"
[ -n "$key" ] || {
echo "Failed to gather public SSH host key for the '$server_addr'." >&2
return 1
}
mkdir -p -m0700 "`dirname "$KNOWN_HOSTS"`"
echo "$key" >> "$KNOWN_HOSTS" || {
echo "Failed to add public SSH host key for the '$server_addr' into '$KNOWN_HOSTS'." >&2
return 1
}
return 0
}
[ $# -ge 1 ] || usage
KNOWN_HOSTS=
update_known_hosts "$@"
[ -f "$KNOWN_HOSTS" ] || {
echo "Known hosts file '$KNOWN_HOSTS' doesn't exist" >&2
exit 1
}
if [ -z "$PLESK_SSH_KEY_PATH" ]
then
ssh -o UserKnownHostsFile="$KNOWN_HOSTS" -o StrictHostKeyChecking=yes -o HashKnownHosts=yes -o BatchMode=yes "$@"
else
ssh -i "$PLESK_SSH_KEY_PATH" -o UserKnownHostsFile="$KNOWN_HOSTS" -o StrictHostKeyChecking=yes -o HashKnownHosts=yes -o BatchMode=yes "$@"
fi

View File

@@ -1,8 +0,0 @@
#!/bin/bash
set -eu
if [ "${1:-}" = "remove" ] ; then
plesk sbin package --remove plesk-git-http || :
else
plesk sbin package --install git plesk-git-http
fi

View File

@@ -1,3 +0,0 @@
#!/bin/bash -e
### Copyright 1999-2025. WebPros International GmbH. All rights reserved.
[ -d "$1" ] && chown -R root:root "$1"

View File

@@ -1,4 +0,0 @@
#!/bin/bash -e
### Copyright 1999-2024. WebPros International GmbH. All rights reserved.
ldd --version | awk '/^ldd/{print $NF}'

View File

@@ -1,89 +0,0 @@
#!/bin/bash
set -eu
die()
{
echo "$*" 1>&2
exit 1
}
NODENV_SRC_PATH="/usr/local/psa/admin/plib/modules/nodejs/libexec/nodenv"
NODENV_DST_BASE_PATH="/usr/libexec"
NODENV_DST_PATH="$NODENV_DST_BASE_PATH/nodenv"
NODENV_TARGET="/usr/bin/nodenv"
HTTPD_SYSTEMD_CONF_DIR="/usr/lib/systemd/system/httpd.service.d"
install_nodenv()
{
chmod 755 "$NODENV_SRC_PATH"/*
cp -rf "$NODENV_SRC_PATH" "$NODENV_DST_BASE_PATH"
if [ ! -e "$NODENV_TARGET" ] ; then
ln -sf "$NODENV_DST_PATH/nodenv" "$NODENV_TARGET"
fi
cp "$NODENV_SRC_PATH/nodenv-init-profile" /etc/profile.d/nodenv.sh
}
remove_nodenv()
{
local nodenv_realpath=$(realpath "$NODENV_TARGET")
if [ "$nodenv_realpath" = "$NODENV_DST_PATH/nodenv" ] ; then
rm $NODENV_TARGET
fi
if [ -d "$NODENV_DST_PATH" ] ; then
rm -rf "$NODENV_DST_PATH"
fi
rm /etc/profile.d/nodenv.sh
if [ "$OS_NAME" = "AlmaLinux" ] && [ "$OS_SHORT_VERSION" = "10" ] && [ -f "$HTTPD_SYSTEMD_CONF_DIR/nodejs.conf" ]; then
rm "$HTTPD_SYSTEMD_CONF_DIR/nodejs.conf"
/bin/systemctl --system daemon-reload
fi
}
do_install()
{
local packages="passenger"
[ "$OS_ARCH" = "x86_64" -o "$OS_ARCH" = "aarch64" ] || die "Unsupported architecture"
case "$OS_PKGTYPE" in
rpm)
packages+=" mod_passenger libatomic"
;;
deb)
packages+=" libapache2-mod-passenger-plesk libatomic1"
;;
*)
die "Unsupported package type $OS_PKGTYPE ($OS_NAME $OS_VERSION): only rpm and deb are supported"
;;
esac
plesk sbin package --install $packages
if [ "$OS_NAME" = "AlmaLinux" -a "$OS_SHORT_VERSION" = "10" ]; then
mkdir -p "$HTTPD_SYSTEMD_CONF_DIR"
cat > "$HTTPD_SYSTEMD_CONF_DIR/nodejs.conf" <<EOF
[Service]
MemoryDenyWriteExecute=no
EOF
/bin/systemctl --system daemon-reload
fi
mkdir -p "/opt/plesk/node"
install_nodenv
}
do_remove()
{
remove_nodenv
}
if [ "${1:-}" = "remove" ] ; then
do_remove
else
do_install
fi

View File

@@ -1,7 +0,0 @@
#!/bin/bash -e
### Copyright 1999-2024. WebPros International GmbH. All rights reserved.
find $1 -type f -print0 | xargs -0 sed -i \
-e "1s,#!/usr/bin/env node,#!${1}/bin/node,g" \
-e '1s,^#!\s*/usr/bin/python\($\|\s\),#!/usr/bin/python2\1,' \
-e '1s,^#!\s*/usr/bin/env\s\+python\($\|\s\),#!/usr/bin/env python2\1,'

View File

@@ -1,4 +0,0 @@
#!/bin/bash -e
### Copyright 1999-2024. WebPros International GmbH. All rights reserved.
$1 -v

View File

@@ -1,4 +0,0 @@
#!/bin/bash -e
### Copyright 1999-2024. WebPros International GmbH. All rights reserved.
$1 install -g $2

View File

@@ -1,10 +0,0 @@
#!/bin/bash -e
### Copyright 1999-2024. WebPros International GmbH. All rights reserved.
[ -d "$2" ] && mv "$2" "$2.back"
mkdir -m 755 "$2"
tar -xf "$1" -C "$2" --unlink-first --strip-components 1 --no-same-owner
find "$2" -type f -print0 | xargs -0 sed -i \
-e "1s,#!/usr/bin/env node,#!${2}/bin/node,g" \
-e '1s,^#!\s*/usr/bin/python\($\|\s\),#!/usr/bin/python2\1,' \
-e '1s,^#!\s*/usr/bin/env\s\+python\($\|\s\),#!/usr/bin/env python2\1,'
[ -d "$2.back" ] && rm -rf "$2.back"

View File

@@ -1,21 +0,0 @@
#!/usr/local/psa/admin/bin/php
<?php
require_once('sdk.php');
pm_Context::init('notifier');
if ($argc < 4) {
$cmd = reset($argv);
echo "Usage: {$cmd} <host> <ports> <timeout>\n";
echo "e.g. {$cmd} smtp.gmail.com 25,587 3\n";
exit(1);
}
$host = $argv[1];
$ports = explode(',', $argv[2]);
$timeout = (int)$argv[3];
$checker = new PleskExt\Notifier\MailPorts\Checker($host, $ports, $timeout);
$list = $checker->run()->detectUnavailablePorts();
echo implode(',', $list) . "\n";
exit(0);

View File

@@ -1,4 +0,0 @@
#!/bin/bash
### Copyright 1999-2024. WebPros International GmbH. All rights reserved.
! rpm -q gpg-pubkey-1bb943db || rpm -q gpg-pubkey-c74cd1d8 || rpm --import "$1"

View File

@@ -1,44 +0,0 @@
#!/opt/plesk/python/3/bin/python
# Copyright 1999-2024. Plesk International GmbH. All rights reserved.
import platform
import os
import sys
if platform.system() != 'Windows':
# Configure migrator so:
# - nobody except root and Plesk user under which migrator is running can read/modify the files.
# - both backend (running as superuser) and frontend (running as "psaadm") could work with the files.
# Expected permissions for files created by backend are:
# rw-rw---- root psaadm
# Expected permissions for directories created by backend are:
# rwxrwx--- root psaadm
# So, frontend could work with files by group "psadm", and backend could work with the files as superuser.
import grp
try:
frontend_group_entry = grp.getgrnam('psaadm')
except KeyError:
frontend_group_entry = None
if frontend_group_entry is not None:
frontend_group_id = frontend_group_entry.gr_gid
os.setegid(frontend_group_id)
# Do not allow others to work with files
os.umask(0o007)
execution_path = __file__
while os.path.islink(execution_path):
execution_path = os.readlink(execution_path)
base_dir = '/usr/local/psa/admin/plib/modules/panel-migrator/backend'
lib_dir = '/usr/local/psa/admin/plib/modules/panel-migrator/backend/lib'
var_dir = '/usr/local/psa/var/modules/panel-migrator'
sys.path.extend([os.path.join(lib_dir, 'python')])
from parallels.core.cli.migration_cli import run
if __name__ == '__main__':
sys.exit(run(base_dir, var_dir, execution_path, sys.argv[1:]))

View File

@@ -1,8 +0,0 @@
#!/bin/bash -e
### Copyright 1999-2017. Plesk International GmbH. All rights reserved.
find /usr/local/psa/var/modules/panel-migrator -type d -exec chmod 770 {} \;
find /usr/local/psa/var/modules/panel-migrator -type f -exec chmod 660 {} \;
find /usr/local/psa/var/modules/panel-migrator -exec chown root:psaadm {} \;
chmod -R o-rwx /var/lib/psa/dumps
chmod -R o-w /usr/local/psa/admin/share/pmmcli
chmod -R o-w /usr/local/psa/var/apspackages

Some files were not shown because too many files have changed in this diff Show More