Files
mailsystem/activate-srs.sh
T

1893 lines
46 KiB
Bash
Executable File

#!/usr/bin/env bash
# ----------
# Selective SRS activation
#
# Activates selective SRS on a prepared mail server.
#
# The script is intentionally conservative:
#
# - ENABLED -> no changes, rc=0
# - DISABLED -> activate after explicit confirmation
# - INCONSISTENT -> abort without changes
#
# Persistent pre-SRS state is read from:
#
# /etc/postfix-srs/state.conf
#
# That state file is never overwritten by this script.
# ----------
# ----------
# Script setup
# ----------
working_dir="$(dirname "$(realpath "$0")")"
# shellcheck source=helpers/srs-common.sh
source "${working_dir}/helpers/srs-common.sh"
trap 'handle_signal' SIGHUP SIGINT SIGTERM
init_srs_runtime
# ----------
# Activation runtime state
# ----------
ACTIVATION_CHANGES_STARTED=false
ACTIVATION_BACKUP_DIR=""
POSTFIX_RELOADED=false
POSTFIX_SRS_DROPIN_WAS_PRESENT=false
SRS_DELIVERY_DROPIN_WAS_PRESENT=false
declare -A SERVICE_WAS_ACTIVE
declare -A SERVICE_WAS_ENABLED
# ----------
# Local helper functions
# ----------
main_cf_explicit_value() {
local parameter="$1"
awk -v parameter="$parameter" '
/^[[:space:]]*#/ { next }
$0 ~ "^[[:space:]]*" parameter "[[:space:]]*=" {
line=$0
}
END {
if (line != "") {
sub("^[[:space:]]*" parameter "[[:space:]]*=[[:space:]]*", "", line)
print line
}
}
' "$POSTFIX_MAIN_CF"
}
main_cf_parameter_is_set() {
local parameter="$1"
grep -Eq \
"^[[:space:]]*${parameter}[[:space:]]*=" \
"$POSTFIX_MAIN_CF"
}
master_service_option_value() {
local service="$1"
local option="$2"
awk -v service="$service" -v option="$option" '
/^[[:space:]]*#/ { next }
$1 == service && $2 == "inet" {
in_service=1
next
}
in_service && $0 !~ /^[[:space:]]/ {
exit
}
in_service && $1 == "-o" {
prefix=option "="
if (index($2, prefix) == 1) {
value=$2
sub("^" option "=", "", value)
print value
exit
}
}
' "$POSTFIX_MASTER_CF"
}
master_srs_forward_present() {
local master_contents
# Read failures must not be indistinguishable from an absent service.
master_contents="$(< "$POSTFIX_MASTER_CF")" || return 2
awk '
/^[[:space:]]*#/ { next }
$1 == "srs-forward" && $2 == "unix" {
found_service=1
next
}
found_service && $0 !~ /^[[:space:]]/ {
exit
}
found_service && $0 ~ /argv=\/usr\/local\/sbin\/srs-forward\.py/ {
found_argv=1
}
END {
if (found_service && found_argv)
exit 0
exit 1
}
' <<< "$master_contents"
}
port_is_listening() {
local host="$1"
local port="$2"
local sockets rc
# Capture the status of ss separately: without this, an ss failure
# can look like an empty socket listing.
sockets="$(ss -ltnH 2>> "$log_file")" || return 2
awk -v host="$host" -v port="$port" '
{
local_address=$4
if (local_address == host ":" port ||
local_address == "[" host "]:" port) {
found=1
exit
}
}
END {
exit(found ? 0 : 1)
}
' <<< "$sockets"
rc=$?
case "$rc" in
0|1) return "$rc" ;;
*) return 2 ;;
esac
}
service_exists() {
systemctl cat "$1" > /dev/null 2>&1
}
read_srs_service_state() {
local output line key value
local load_state="" active_state="" enabled_state=""
SRS_SERVICE_ACTIVE_STATE=""
SRS_SERVICE_ENABLED_STATE=""
output="$(systemctl show "$1" --no-pager \
-p LoadState -p ActiveState -p UnitFileState 2>> "$log_file")" || return 2
while IFS= read -r line ; do
key="${line%%=*}"
value="${line#*=}"
[[ "$line" == *=* ]] || return 2
case "$key" in
LoadState)
[[ -z "$load_state" ]] || return 2
load_state="$value"
;;
ActiveState)
[[ -z "$active_state" ]] || return 2
active_state="$value"
;;
UnitFileState)
[[ -z "$enabled_state" ]] || return 2
enabled_state="$value"
;;
*) return 2 ;;
esac
done <<< "$output"
[[ "$load_state" == "loaded" ]] || return 2
case "$active_state" in
active|inactive) ;;
*) return 2 ;;
esac
case "$enabled_state" in
enabled|enabled-runtime|disabled) ;;
*) return 2 ;;
esac
SRS_SERVICE_ACTIVE_STATE="$active_state"
SRS_SERVICE_ENABLED_STATE="$enabled_state"
return 0
}
service_active() {
read_srs_service_state "$1" || return 2
[[ "$SRS_SERVICE_ACTIVE_STATE" == "active" ]]
}
service_enabled_state() {
read_srs_service_state "$1" || return 2
printf '%s\n' "$SRS_SERVICE_ENABLED_STATE"
}
postsrsd_srs_domain() {
awk '
/^[[:space:]]*#/ { next }
/^[[:space:]]*srs-domain[[:space:]]*=/ {
line=$0
sub(/^[^=]*=[[:space:]]*/, "", line)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", line)
gsub(/^"|"$/, "", line)
print line
exit
}
' "$POSTSRSD_CONF_FILE"
}
srs_alias_tool() {
local action="$1"
python3 "$SRS_ALIAS_HELPER" "$action" \
--main-cf "$POSTFIX_MAIN_CF" \
--domain "$_SRS_DOMAIN" \
--reverse-map "socketmap:inet:${SRS_REVERSE_SOCKET_HOST}:${SRS_REVERSE_SOCKET_PORT}:reverse"
}
# Upgrade an already running instance without touching binaries/systemd units.
# A new snapshot is taken on every attempt and restored on any failure.
upgrade_existing_srs_aliases() {
local action="$1" folder snapshot
folder="/root/postfix-srs-alias-upgrade-${backup_date}"
snapshot="${folder}/main.cf"
mkdir -m 0700 "$folder" || fatal "Cannot create alias upgrade backup directory."
cp -a "$POSTFIX_MAIN_CF" "$snapshot" || fatal "Cannot snapshot main.cf for alias upgrade."
echononl "Track incoming SRS bounce aliases (${action}).."
if srs_alias_tool "$action" > "$log_file" 2>&1 &&
postfix check >> "$log_file" 2>&1 &&
[[ "$(srs_alias_tool status 2>>"$log_file")" == 'managed' ]] &&
{ [[ "$action" == 'adopt' ]] || systemctl reload "$POSTFIX_SERVICE" >> "$log_file" 2>&1; }
then
echo_ok
info "SRS inbound alias settings now managed. Backup: ${snapshot}"
clean_up 0
fi
echo_failed
error "Alias upgrade failed: $(cat "$log_file")"
# A pure adoption changes only a comment. Never reload Postfix on
# either the success or rollback path for that operation.
if cp -a "$snapshot" "$POSTFIX_MAIN_CF" &&
postfix check > "$log_file" 2>&1 &&
{ [[ "$action" == 'adopt' ]] || systemctl reload "$POSTFIX_SERVICE" >> "$log_file" 2>&1; }
then
fatal "Alias upgrade failed; previous main.cf restored successfully."
fi
fatal "Alias upgrade failed; automatic restore incomplete. Manual review: ${snapshot}"
}
state_main_cf_matches() {
local parameter="$1"
local was_set="$2"
local expected_value="$3"
local current_value=""
if "$was_set" ; then
if ! main_cf_parameter_is_set "$parameter" ; then
return 1
fi
current_value="$(main_cf_explicit_value "$parameter")"
[[ "$current_value" == "$expected_value" ]]
return
fi
! main_cf_parameter_is_set "$parameter"
}
state_master_option_matches() {
local service="$1"
local option="$2"
local was_set="$3"
local expected_value="$4"
local current_value=""
current_value="$(master_service_option_value "$service" "$option")"
if "$was_set" ; then
[[ "$current_value" == "$expected_value" ]]
return
fi
[[ -z "$current_value" ]]
}
csv_add_value() {
local current="$1"
local add="$2"
local item
local result=""
local found=false
IFS=',' read -r -a _items <<< "$current"
for item in "${_items[@]}" ; do
item="${item#"${item%%[![:space:]]*}"}"
item="${item%"${item##*[![:space:]]}"}"
[[ -z "$item" ]] && continue
if [[ "$item" == "$add" ]]; then
found=true
fi
if [[ -z "$result" ]]; then
result="$item"
else
result="${result},${item}"
fi
done
if ! $found ; then
if [[ -z "$result" ]]; then
result="$add"
else
result="${result},${add}"
fi
fi
printf '%s\n' "$result"
}
csv_remove_value() {
local current="$1"
local remove="$2"
local item
local result=""
IFS=',' read -r -a _items <<< "$current"
for item in "${_items[@]}" ; do
item="${item#"${item%%[![:space:]]*}"}"
item="${item%"${item##*[![:space:]]}"}"
[[ -z "$item" ]] && continue
[[ "$item" == "$remove" ]] && continue
if [[ -z "$result" ]]; then
result="$item"
else
result="${result},${item}"
fi
done
printf '%s\n' "$result"
}
update_master_service_option() {
local service="$1"
local option="$2"
local value="$3"
python3 - \
"$POSTFIX_MASTER_CF" \
"$service" \
"$option" \
"$value" <<'PY_EOF'
import os
import re
import stat
import sys
import tempfile
path, service, option, value = sys.argv[1:5]
with open(path, "r", encoding="utf-8") as f:
lines = f.readlines()
service_index = None
for idx, line in enumerate(lines):
if not line.strip() or line.lstrip().startswith("#"):
continue
fields = line.split()
if len(fields) >= 2 and fields[0] == service and fields[1] == "inet":
service_index = idx
break
if service_index is None:
raise SystemExit(2)
end_index = len(lines)
for idx in range(service_index + 1, len(lines)):
line = lines[idx]
if line.strip() == "":
end_index = idx
break
if line[0].isspace():
continue
if line.lstrip().startswith("#"):
end_index = idx
break
end_index = idx
break
option_re = re.compile(
r"^(?P<indent>\s*)-o\s+" + re.escape(option) + r"=.*(?:\n)?$"
)
option_index = None
option_indent = " "
for idx in range(service_index + 1, end_index):
match = option_re.match(lines[idx])
if match:
option_index = idx
option_indent = match.group("indent") or " "
break
if value:
new_line = f"{option_indent}-o {option}={value}\n"
if option_index is not None:
lines[option_index] = new_line
else:
lines.insert(end_index, new_line)
else:
if option_index is not None:
del lines[option_index]
st = os.stat(path)
directory = os.path.dirname(path)
fd, tmp_path = tempfile.mkstemp(prefix=".master.cf.srs.", dir=directory)
try:
with os.fdopen(fd, "w", encoding="utf-8") as f:
f.writelines(lines)
os.chmod(tmp_path, stat.S_IMODE(st.st_mode))
os.chown(tmp_path, st.st_uid, st.st_gid)
os.replace(tmp_path, path)
finally:
if os.path.exists(tmp_path):
os.unlink(tmp_path)
PY_EOF
}
append_main_cf_managed_block() {
local tmp
tmp="$(mktemp "${POSTFIX_CONF_DIR}/.main.cf.srs.XXXXXX")" || return 1
if ! cp -a "$POSTFIX_MAIN_CF" "$tmp" ; then
rm -f "$tmp"
return 1
fi
cat >> "$tmp" <<EOF
${SRS_MAIN_CF_BEGIN_MARKER}
# ============================================================================
# Selective Sender Rewriting Scheme (SRS)
#
# ACHTUNG: AUTOMATISCH VERWALTETER KONFIGURATIONSBLOCK
#
# Dieser Block wird von den SRS-Verwaltungs-Scripten automatisch erzeugt
# und gepflegt. Er sollte nicht manuell veraendert werden.
#
# Start- und End-Marker duerfen nicht umbenannt oder entfernt werden.
# Manuelle Aenderungen innerhalb dieses Blocks koennen bei einem spaeteren
# Installations-, Update-, Enable- oder Disable-Lauf ueberschrieben werden.
# ============================================================================
# ID: postfix-selective-srs
# Version: 2
# State: enabled
#
# default_transport leitet Empfaenger zunaechst an den selektiven
# srs-forward Transport. Das Entscheidungsscript entscheidet je Empfaenger,
# ob SRS notwendig ist oder die Nachricht unveraendert weitergegeben wird.
#
# Der recipient limit von 1 stellt sicher, dass die Entscheidung fuer jeden
# Empfaenger einzeln getroffen werden kann.
#
# recipient_canonical_maps dient der Rueckumsetzung eingehender SRS-Adressen.
#
default_transport = srs-forward
srs-forward_destination_recipient_limit = 1
recipient_canonical_maps = socketmap:inet:${SRS_REVERSE_SOCKET_HOST}:${SRS_REVERSE_SOCKET_PORT}:reverse
${SRS_MAIN_CF_END_MARKER}
EOF
if ! mv "$tmp" "$POSTFIX_MAIN_CF" ; then
rm -f "$tmp"
return 1
fi
return 0
}
append_master_cf_managed_block() {
local tmp
tmp="$(mktemp "${POSTFIX_CONF_DIR}/.master.cf.srs.XXXXXX")" || return 1
if ! cp -a "$POSTFIX_MASTER_CF" "$tmp" ; then
rm -f "$tmp"
return 1
fi
cat >> "$tmp" <<'EOF'
# BEGIN OOPEN-SRS-MANAGED
# ============================================================================
# Selective Sender Rewriting Scheme (SRS)
#
# This block is maintained by the SRS management scripts.
# Do not rename or remove the BEGIN/END markers.
# ============================================================================
srs-forward unix - n n - - pipe
flags=Rq null_sender= user=nobody
argv=/usr/local/sbin/srs-forward.py ${sender} ${recipient} ${original_recipient} ${queue_id} envid=${envid}
# END OOPEN-SRS-MANAGED
EOF
if ! mv "$tmp" "$POSTFIX_MASTER_CF" ; then
rm -f "$tmp"
return 1
fi
return 0
}
snapshot_systemd_dropins() {
if [[ -f "$POSTFIX_SRS_DROPIN_FILE" ]]; then
POSTFIX_SRS_DROPIN_WAS_PRESENT=true
cp -a "$POSTFIX_SRS_DROPIN_FILE" \
"${ACTIVATION_BACKUP_DIR}/postfix.service-srs.conf" || return 1
fi
if [[ -f "$SRS_DELIVERY_DROPIN_FILE" ]]; then
SRS_DELIVERY_DROPIN_WAS_PRESENT=true
cp -a "$SRS_DELIVERY_DROPIN_FILE" \
"${ACTIVATION_BACKUP_DIR}/postfix@srs-delivery.service-srs.conf" || return 1
fi
return 0
}
write_srs_systemd_dropins() {
mkdir -p "$POSTFIX_SRS_DROPIN_DIR" "$SRS_DELIVERY_DROPIN_DIR" || return 1
cat > "$POSTFIX_SRS_DROPIN_FILE" <<EOF
[Unit]
Wants=${SRS_REVERSE_MAP_SERVICE} ${SRS_DELIVERY_SERVICE}
After=${SRS_REVERSE_MAP_SERVICE} ${SRS_DELIVERY_SERVICE}
EOF
cat > "$SRS_DELIVERY_DROPIN_FILE" <<EOF
[Unit]
Wants=${POSTSRSD_SERVICE}
After=${POSTSRSD_SERVICE}
EOF
chown root:root \
"$POSTFIX_SRS_DROPIN_FILE" \
"$SRS_DELIVERY_DROPIN_FILE" || return 1
chmod 0644 \
"$POSTFIX_SRS_DROPIN_FILE" \
"$SRS_DELIVERY_DROPIN_FILE" || return 1
systemctl daemon-reload || return 1
return 0
}
restore_systemd_dropins() {
local restore_failed=false
if $POSTFIX_SRS_DROPIN_WAS_PRESENT ; then
cp -a \
"${ACTIVATION_BACKUP_DIR}/postfix.service-srs.conf" \
"$POSTFIX_SRS_DROPIN_FILE" || restore_failed=true
else
rm -f "$POSTFIX_SRS_DROPIN_FILE" || restore_failed=true
fi
if $SRS_DELIVERY_DROPIN_WAS_PRESENT ; then
cp -a \
"${ACTIVATION_BACKUP_DIR}/postfix@srs-delivery.service-srs.conf" \
"$SRS_DELIVERY_DROPIN_FILE" || restore_failed=true
else
rm -f "$SRS_DELIVERY_DROPIN_FILE" || restore_failed=true
fi
systemctl daemon-reload || restore_failed=true
! $restore_failed
}
snapshot_service_states() {
local service
local -A snapshot_active=() snapshot_enabled=()
for service in \
"$POSTSRSD_SERVICE" \
"$SRS_REVERSE_MAP_SERVICE" \
"$SRS_DELIVERY_SERVICE"
do
if ! read_srs_service_state "$service" ; then
warn "Cannot determine a supported systemd state for '${service}'."
return 1
fi
# The caller has classified this installation as DISABLED. Reject
# a state transition since that check rather than capturing an
# unexpectedly started/enabled service as the rollback baseline.
if [[ "$SRS_SERVICE_ACTIVE_STATE" != "inactive" ||
"$SRS_SERVICE_ENABLED_STATE" != "disabled" ]]; then
warn "SRS service '${service}' changed state before activation."
return 1
fi
snapshot_active["$service"]="false"
snapshot_enabled["$service"]="$SRS_SERVICE_ENABLED_STATE"
done
# Only publish a complete, validated snapshot.
for service in \
"$POSTSRSD_SERVICE" \
"$SRS_REVERSE_MAP_SERVICE" \
"$SRS_DELIVERY_SERVICE"
do
SERVICE_WAS_ACTIVE["$service"]="${snapshot_active[$service]}"
SERVICE_WAS_ENABLED["$service"]="${snapshot_enabled[$service]}"
done
return 0
}
restore_service_states() {
local service
local restore_failed=false
local enabled_state active_state
# Validate the entire snapshot before changing *any* unit.
for service in \
"$POSTSRSD_SERVICE" \
"$SRS_REVERSE_MAP_SERVICE" \
"$SRS_DELIVERY_SERVICE"
do
enabled_state="${SERVICE_WAS_ENABLED[$service]:-}"
active_state="${SERVICE_WAS_ACTIVE[$service]:-}"
case "$enabled_state" in
enabled|enabled-runtime|disabled) ;;
*) warn "Invalid saved enable state for '${service}': '${enabled_state}'."; return 1 ;;
esac
case "$active_state" in
true|false) ;;
*) warn "Invalid saved active state for '${service}': '${active_state}'."; return 1 ;;
esac
done
for service in \
"$POSTSRSD_SERVICE" \
"$SRS_REVERSE_MAP_SERVICE" \
"$SRS_DELIVERY_SERVICE"
do
enabled_state="${SERVICE_WAS_ENABLED[$service]}"
case "$enabled_state" in
enabled)
systemctl enable "$service" > /dev/null 2>> "$log_file" || restore_failed=true
;;
enabled-runtime)
systemctl enable --runtime "$service" > /dev/null 2>> "$log_file" || restore_failed=true
;;
disabled)
systemctl disable "$service" > /dev/null 2>> "$log_file" || restore_failed=true
;;
esac
if [[ "${SERVICE_WAS_ACTIVE[$service]}" == "true" ]]; then
systemctl start "$service" > /dev/null 2>> "$log_file" || restore_failed=true
else
systemctl stop "$service" > /dev/null 2>> "$log_file" || restore_failed=true
fi
done
! $restore_failed
}
rollback_activation() {
local rollback_failed=false
if ! $ACTIVATION_CHANGES_STARTED ; then
return 0
fi
blank_line
warn "SRS activation failed. Trying to restore the previous state."
if [[ -n "$ACTIVATION_BACKUP_DIR" &&
-r "${ACTIVATION_BACKUP_DIR}/main.cf" &&
-r "${ACTIVATION_BACKUP_DIR}/master.cf" ]]
then
echononl "Restore '${POSTFIX_MAIN_CF}'.."
if cp -a "${ACTIVATION_BACKUP_DIR}/main.cf" "$POSTFIX_MAIN_CF" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
rollback_failed=true
fi
echononl "Restore '${POSTFIX_MASTER_CF}'.."
if cp -a "${ACTIVATION_BACKUP_DIR}/master.cf" "$POSTFIX_MASTER_CF" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
rollback_failed=true
fi
else
error "Activation backup is incomplete. Cannot automatically restore Postfix configuration."
rollback_failed=true
fi
echononl "Restore previous systemd SRS drop-ins.."
if restore_systemd_dropins ; then
echo_ok
else
echo_failed
rollback_failed=true
fi
echononl "Restore previous SRS service states.."
if restore_service_states ; then
echo_ok
else
echo_failed
rollback_failed=true
fi
echononl "Check restored Postfix configuration.."
if postfix check > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
rollback_failed=true
fi
if systemctl is-active --quiet "$POSTFIX_SERVICE" ; then
echononl "Reload restored Postfix configuration.."
if systemctl reload "$POSTFIX_SERVICE" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
rollback_failed=true
fi
else
echononl "Check primary Postfix service '${POSTFIX_SERVICE}' is active.."
echo_failed
warn "Primary Postfix is inactive; restored configuration could not be reloaded."
rollback_failed=true
fi
if $rollback_failed ; then
error "Automatic rollback could not fully restore the previous state. Manual intervention is required."
return 1
fi
info "Previous state was successfully restored."
return 0
}
fatal_with_activation_rollback() {
local message="$1"
if $ACTIVATION_CHANGES_STARTED ; then
if rollback_activation ; then
ACTIVATION_CHANGES_STARTED=false
fatal "${message} The previous state was successfully restored."
else
fatal "${message} Automatic rollback could not fully restore the previous state."
fi
fi
fatal "$message"
}
handle_signal() {
trap - SIGHUP SIGINT SIGTERM
warn "Activation interrupted by signal."
if $ACTIVATION_CHANGES_STARTED ; then
rollback_activation
fi
clean_up 1
}
# ----------
# Header
# ----------
blank_line
echo -e "\033[1m----------\033[m"
echo -e "\033[32m\033[1mRunning script \033[m\033[1m${script_name}\033[32m .. \033[m"
echo -e "\033[1m----------\033[m"
blank_line
# ----------
# Basic checks
# ----------
check_root
check_required_commands \
awk \
cp \
cut \
grep \
hostname \
mkdir \
mktemp \
mv \
postfix \
rm \
python3 \
realpath \
sed \
ss \
stat \
systemctl
load_srs_config
load_srs_state
[[ -f "$SRS_ALIAS_HELPER" && ! -L "$SRS_ALIAS_HELPER" ]] ||
fatal "Missing regular SRS alias helper: ${SRS_ALIAS_HELPER}"
smtp_pre_value=""
amavis_pre_value=""
if $_PRE_SRS_SMTP_RECEIVE_OVERRIDE_OPTIONS_SET ; then
smtp_pre_value="$_PRE_SRS_SMTP_RECEIVE_OVERRIDE_OPTIONS"
fi
if $_PRE_SRS_AMAVIS_RECEIVE_OVERRIDE_OPTIONS_SET ; then
amavis_pre_value="$_PRE_SRS_AMAVIS_RECEIVE_OVERRIDE_OPTIONS"
fi
smtp_active_value="$(csv_add_value "$smtp_pre_value" "no_address_mappings")"
amavis_active_value="$(csv_remove_value "$amavis_pre_value" "no_address_mappings")"
# ----------
# Check required installation files
# ----------
blank_line
echo -e "\033[37m\033[1mCheck selective SRS installation..\033[m"
blank_line
installation_ok=true
for _file in \
"$POSTFIX_MAIN_CF" \
"$POSTFIX_MASTER_CF" \
"$POSTSRSD_CONF_FILE" \
"$POSTSRSD_SECRET_FILE" \
"${POSTFIX_SRS_DELIVERY_DIR}/main.cf" \
"${POSTFIX_SRS_DELIVERY_DIR}/master.cf" \
"${POSTFIX_SRS_DELIVERY_DIR}/transport" \
"${POSTFIX_SRS_DELIVERY_DIR}/transport.db"
do
echononl "Check file '${_file}'.."
if [[ -r "$_file" ]]; then
echo_ok
else
echo_failed
installation_ok=false
fi
done
for _script in \
"$SRS_ALIAS_DECISION_SCRIPT" \
"$SRS_FORWARD_SCRIPT" \
"$SRS_REVERSE_MAP_SCRIPT" \
"$SRS_REVERSE_POLICY_SCRIPT"
do
echononl "Check executable '${_script}'.."
if [[ -x "$_script" ]]; then
echo_ok
else
echo_failed
installation_ok=false
fi
done
echononl "Check configured PostSRSd SRS domain.."
if [[ "$(postsrsd_srs_domain)" == "$_SRS_DOMAIN" ]]; then
echo_ok
else
echo_failed
installation_ok=false
fi
# ----------
# Check systemd services
# ----------
blank_line
echo -e "\033[37m\033[1mCheck selective SRS services..\033[m"
blank_line
services_exist=true
services_active=true
services_enabled=true
services_disabled=true
services_status_known=true
for _service in \
"$POSTSRSD_SERVICE" \
"$SRS_REVERSE_MAP_SERVICE" \
"$SRS_DELIVERY_SERVICE"
do
echononl "Check systemd service '${_service}' exists.."
if service_exists "$_service" ; then
echo_ok
else
echo_failed
services_exist=false
services_active=false
services_enabled=false
services_disabled=false
services_status_known=false
continue
fi
echononl "Read systemd state of '${_service}'.."
if ! read_srs_service_state "$_service" ; then
echo_failed
services_status_known=false
services_active=false
services_enabled=false
services_disabled=false
continue
fi
echo_ok
if [[ "$SRS_SERVICE_ACTIVE_STATE" != "active" ]]; then
services_active=false
fi
if [[ "$SRS_SERVICE_ENABLED_STATE" == "disabled" ]]; then
services_enabled=false
fi
if [[ "$SRS_SERVICE_ACTIVE_STATE" != "inactive" ||
"$SRS_SERVICE_ENABLED_STATE" != "disabled" ]]; then
services_disabled=false
fi
done
echononl "Check main Postfix service '${POSTFIX_SERVICE}' is active.."
primary_postfix_active=false
if systemctl is-active --quiet "$POSTFIX_SERVICE" ; then
echo_ok
primary_postfix_active=true
else
echo_failed
fi
# ----------
# Check listeners
# ----------
blank_line
echo -e "\033[37m\033[1mCheck selective SRS listeners..\033[m"
blank_line
listeners_ok=true
listeners_absent=true
listeners_status_known=true
while IFS='|' read -r _label _host _port ; do
port_is_listening "$_host" "$_port"
_port_rc=$?
case "$_port_rc" in
0)
echononl "Check ${_label} state on ${_host}:${_port} (listening).."
echo_ok
listeners_absent=false
;;
1)
echononl "Check ${_label} state on ${_host}:${_port} (inactive).."
echo_ok
listeners_ok=false
;;
*)
echononl "Check ${_label} state on ${_host}:${_port} (query failed).."
echo_failed
listeners_ok=false
listeners_absent=false
listeners_status_known=false
;;
esac
done <<EOF
PostSRSd socketmap|${POSTSRSD_SOCKET_HOST}|${POSTSRSD_SOCKET_PORT}
SRS reverse socketmap|${SRS_REVERSE_SOCKET_HOST}|${SRS_REVERSE_SOCKET_PORT}
SRS reinjection listener|${SRS_REINJECT_HOST}|${SRS_REINJECT_PORT}
SRS reverse listener|${SRS_REVERSE_HOST}|${SRS_REVERSE_PORT}
EOF
dropins_absent=true
for _dropin in "$POSTFIX_SRS_DROPIN_FILE" "$SRS_DELIVERY_DROPIN_FILE" ; do
if [[ -e "$_dropin" || -L "$_dropin" ]]; then
dropins_absent=false
fi
done
# ----------
# Determine main.cf state
# ----------
blank_line
echo -e "\033[37m\033[1mCheck main Postfix SRS integration..\033[m"
blank_line
main_block_status="invalid"
check_managed_block_markers \
"$POSTFIX_MAIN_CF" \
"$SRS_MAIN_CF_BEGIN_MARKER" \
"$SRS_MAIN_CF_END_MARKER"
_marker_rc=$?
case "$_marker_rc" in
0)
main_block_status="present"
echononl "Validate managed SRS block state in '${POSTFIX_MAIN_CF}'.."
echo_ok
;;
1)
main_block_status="absent"
echononl "Validate managed SRS block state in '${POSTFIX_MAIN_CF}'.."
echo_ok
;;
*)
main_block_status="invalid"
echononl "Validate managed SRS block state in '${POSTFIX_MAIN_CF}'.."
echo_failed
;;
esac
main_srs_values_ok=true
echononl "Validate 'default_transport' state.."
if [[ "$(main_cf_explicit_value default_transport)" == "srs-forward" ]]; then
echo_ok
elif state_main_cf_matches \
default_transport \
"$_PRE_SRS_DEFAULT_TRANSPORT_SET" \
"$_PRE_SRS_DEFAULT_TRANSPORT"
then
echo_ok
main_srs_values_ok=false
else
echo_differs
main_srs_values_ok=false
fi
echononl "Validate 'srs-forward_destination_recipient_limit' state.."
if [[ "$(main_cf_explicit_value srs-forward_destination_recipient_limit)" == "1" ]]; then
echo_ok
elif state_main_cf_matches \
srs-forward_destination_recipient_limit \
"$_PRE_SRS_SRS_FORWARD_DESTINATION_RECIPIENT_LIMIT_SET" \
"$_PRE_SRS_SRS_FORWARD_DESTINATION_RECIPIENT_LIMIT"
then
echo_ok
main_srs_values_ok=false
else
echo_differs
main_srs_values_ok=false
fi
echononl "Validate 'recipient_canonical_maps' state.."
if [[ "$(main_cf_explicit_value recipient_canonical_maps)" == \
"socketmap:inet:${SRS_REVERSE_SOCKET_HOST}:${SRS_REVERSE_SOCKET_PORT}:reverse" ]]
then
echo_ok
elif state_main_cf_matches \
recipient_canonical_maps \
"$_PRE_SRS_RECIPIENT_CANONICAL_MAPS_SET" \
"$_PRE_SRS_RECIPIENT_CANONICAL_MAPS"
then
echo_ok
main_srs_values_ok=false
else
echo_differs
main_srs_values_ok=false
fi
# ----------
# Determine master.cf state
# ----------
blank_line
echo -e "\033[37m\033[1mCheck Postfix master.cf SRS integration..\033[m"
blank_line
master_block_status="invalid"
check_managed_block_markers \
"$POSTFIX_MASTER_CF" \
"$SRS_MASTER_CF_BEGIN_MARKER" \
"$SRS_MASTER_CF_END_MARKER"
_master_marker_rc=$?
case "$_master_marker_rc" in
0)
master_block_status="present"
echononl "Validate managed SRS block state in '${POSTFIX_MASTER_CF}'.."
echo_ok
;;
1)
master_block_status="absent"
echononl "Validate managed SRS block state in '${POSTFIX_MASTER_CF}'.."
echo_ok
;;
*)
master_block_status="invalid"
echononl "Validate managed SRS block state in '${POSTFIX_MASTER_CF}'.."
echo_failed
;;
esac
master_srs_forward_ok=false
master_srs_forward_known=true
smtp_override_ok=false
amavis_override_ok=false
echononl "Validate 'srs-forward' pipe service state.."
master_srs_forward_present
_master_service_rc=$?
case "$_master_service_rc" in
0)
echo_ok
master_srs_forward_ok=true
;;
1)
# Absent is valid in the stored pre-SRS state.
echo_ok
;;
*)
echo_failed
master_srs_forward_known=false
;;
esac
echononl "Validate port 25 receive_override_options state.."
if [[ "$(master_service_option_value smtp receive_override_options)" == "$smtp_active_value" ]]; then
echo_ok
smtp_override_ok=true
elif state_master_option_matches \
smtp \
receive_override_options \
"$_PRE_SRS_SMTP_RECEIVE_OVERRIDE_OPTIONS_SET" \
"$_PRE_SRS_SMTP_RECEIVE_OVERRIDE_OPTIONS"
then
echo_ok
else
echo_differs
fi
echononl "Validate AmaViS reinjection receive_override_options state.."
if [[ "$(master_service_option_value localhost:10025 receive_override_options)" == "$amavis_active_value" ]]
then
echo_ok
amavis_override_ok=true
elif state_master_option_matches \
localhost:10025 \
receive_override_options \
"$_PRE_SRS_AMAVIS_RECEIVE_OVERRIDE_OPTIONS_SET" \
"$_PRE_SRS_AMAVIS_RECEIVE_OVERRIDE_OPTIONS"
then
echo_ok
else
echo_differs
fi
# ----------
# Validate against active and pre-SRS states
# ----------
blank_line
echo -e "\033[37m\033[1mValidate current Postfix configuration against active/pre-SRS states..\033[m"
blank_line
pre_srs_main_ok=true
pre_srs_master_ok=true
echononl "Validate 'default_transport' transition.."
if state_main_cf_matches \
default_transport \
"$_PRE_SRS_DEFAULT_TRANSPORT_SET" \
"$_PRE_SRS_DEFAULT_TRANSPORT"
then
echo_ok
elif [[ "$(main_cf_explicit_value default_transport)" == "srs-forward" ]]; then
echo_ok
pre_srs_main_ok=false
else
echo_differs
pre_srs_main_ok=false
fi
echononl "Validate 'recipient_canonical_maps' transition.."
if state_main_cf_matches \
recipient_canonical_maps \
"$_PRE_SRS_RECIPIENT_CANONICAL_MAPS_SET" \
"$_PRE_SRS_RECIPIENT_CANONICAL_MAPS"
then
echo_ok
elif [[ "$(main_cf_explicit_value recipient_canonical_maps)" == \
"socketmap:inet:${SRS_REVERSE_SOCKET_HOST}:${SRS_REVERSE_SOCKET_PORT}:reverse" ]]
then
echo_ok
pre_srs_main_ok=false
else
echo_differs
pre_srs_main_ok=false
fi
echononl "Validate recipient limit transition.."
if state_main_cf_matches \
srs-forward_destination_recipient_limit \
"$_PRE_SRS_SRS_FORWARD_DESTINATION_RECIPIENT_LIMIT_SET" \
"$_PRE_SRS_SRS_FORWARD_DESTINATION_RECIPIENT_LIMIT"
then
echo_ok
elif [[ "$(main_cf_explicit_value srs-forward_destination_recipient_limit)" == "1" ]]; then
echo_ok
pre_srs_main_ok=false
else
echo_differs
pre_srs_main_ok=false
fi
echononl "Validate port 25 receive_override_options transition.."
if state_master_option_matches \
smtp \
receive_override_options \
"$_PRE_SRS_SMTP_RECEIVE_OVERRIDE_OPTIONS_SET" \
"$_PRE_SRS_SMTP_RECEIVE_OVERRIDE_OPTIONS"
then
echo_ok
elif [[ "$(master_service_option_value smtp receive_override_options)" == "$smtp_active_value" ]]; then
echo_ok
pre_srs_master_ok=false
else
echo_differs
pre_srs_master_ok=false
fi
echononl "Validate AmaViS receive_override_options transition.."
if state_master_option_matches \
localhost:10025 \
receive_override_options \
"$_PRE_SRS_AMAVIS_RECEIVE_OVERRIDE_OPTIONS_SET" \
"$_PRE_SRS_AMAVIS_RECEIVE_OVERRIDE_OPTIONS"
then
echo_ok
elif [[ "$(master_service_option_value localhost:10025 receive_override_options)" == "$amavis_active_value" ]]
then
echo_ok
pre_srs_master_ok=false
else
echo_differs
pre_srs_master_ok=false
fi
# ----------
# Determine selective SRS state
# ----------
srs_integration_enabled=false
srs_integration_disabled=false
srs_runtime_ready=false
activation_ready=false
srs_state="inconsistent"
if [[ "$main_block_status" == "present" ]] &&
[[ "$master_block_status" != "invalid" ]] &&
$master_srs_forward_known &&
$main_srs_values_ok &&
$master_srs_forward_ok &&
$smtp_override_ok &&
$amavis_override_ok
then
srs_integration_enabled=true
fi
if [[ "$main_block_status" == "absent" ]] &&
[[ "$master_block_status" == "absent" ]] &&
$master_srs_forward_known &&
$pre_srs_main_ok &&
$pre_srs_master_ok &&
! $master_srs_forward_ok
then
srs_integration_disabled=true
fi
if $installation_ok &&
$services_exist &&
$services_status_known &&
$services_active &&
$services_enabled &&
$primary_postfix_active &&
$listeners_status_known &&
$listeners_ok
then
srs_runtime_ready=true
fi
if $installation_ok &&
$services_exist
then
activation_ready=true
fi
if $srs_integration_enabled && $srs_runtime_ready ; then
srs_state="enabled"
elif $srs_integration_disabled &&
$services_exist &&
$services_status_known &&
$services_disabled &&
$primary_postfix_active &&
$listeners_status_known &&
$listeners_absent &&
$dropins_absent
then
srs_state="disabled"
else
srs_state="inconsistent"
fi
# ----------
# Summary
# ----------
master_block_summary="$master_block_status"
if [[ "$master_block_status" == "absent" && "$srs_state" == "enabled" ]]; then
master_block_summary="absent (legacy accepted)"
fi
blank_line
echo -e "\033[37m\033[1mSelective SRS summary:\033[m"
blank_line
echo " SRS domain.....................................: ${_SRS_DOMAIN}"
echo " Persistent state..............................: ${SRS_STATE_FILE}"
echo " State origin..................................: ${_STATE_ORIGIN}"
echo ""
echo " Managed main.cf block.........................: ${main_block_status}"
echo " Managed master.cf block.......................: ${master_block_summary}"
echo " SRS main.cf values............................: ${main_srs_values_ok}"
echo " srs-forward master.cf service.................: ${master_srs_forward_ok}"
echo " Port 25 no_address_mappings...................: ${smtp_override_ok}"
echo " AmaViS without no_address_mappings............: ${amavis_override_ok}"
echo ""
echo " SRS installation files........................: ${installation_ok}"
echo " SRS services exist............................: ${services_exist}"
echo " SRS services active...........................: ${services_active}"
echo " SRS listeners.................................: ${listeners_ok}"
echo ""
echo " Current main.cf matches stored pre-SRS state..: ${pre_srs_main_ok}"
echo " Current master.cf matches stored pre-SRS state: ${pre_srs_master_ok}"
echo ""
case "$srs_state" in
enabled)
echo -e " Current selective SRS state....................: \033[32m\033[1mENABLED\033[m"
;;
disabled)
echo -e " Current selective SRS state....................: \033[33m\033[1mDISABLED\033[m"
;;
*)
echo -e " Current selective SRS state....................: \033[31m\033[1mINCONSISTENT\033[m"
;;
esac
blank_line
# ----------
# Handle detected state
# ----------
# A running v1 installation can be upgraded without reinstalling PostSRSd.
srs_alias_status="$(srs_alias_tool status 2>"$log_file")" ||
fatal "Unsafe virtual alias configuration: $(cat "$log_file")"
if [[ "$srs_state" == "enabled" ]]; then
case "$srs_alias_status" in
managed)
info "Selective SRS with inbound bounce reception is already enabled. Nothing to do."
clean_up 0
;;
absent|legacy)
warn "SRS is enabled but bounce alias ownership is not tracked (${srs_alias_status})."
info "Only virtual alias parameters will be updated; PostSRSd binaries and services remain untouched."
if ! ask_yes_no "Upgrade incoming SRS alias management" "no"; then
info "Upgrade cancelled without changes."
clean_up 0
fi
if [[ "$srs_alias_status" == 'legacy' ]]; then
upgrade_existing_srs_aliases adopt
else
upgrade_existing_srs_aliases add
fi
;;
*) fatal "Unexpected SRS alias status: ${srs_alias_status}" ;;
esac
fi
if [[ "$srs_state" == "inconsistent" ]]; then
error "Selective SRS configuration is inconsistent. No changes were made."
clean_up 1
fi
if ! $activation_ready ; then
fatal "Selective SRS is disabled, but the installation is incomplete. Activation is not possible."
fi
[[ "$srs_alias_status" == 'absent' ]] ||
fatal "SRS disabled but alias entries are not absent. Refusing activation."
# ----------
# Activation summary
# ----------
blank_line
echo -e "\033[37m\033[1mSelective SRS activation settings:\033[m"
blank_line
echo " Current state.................................: DISABLED"
echo " Target state..................................: ENABLED"
echo " SRS domain....................................: ${_SRS_DOMAIN}"
echo ""
echo " main.cf.......................................: ${POSTFIX_MAIN_CF}"
echo " master.cf.....................................: ${POSTFIX_MASTER_CF}"
echo ""
echo " Port 25 receive_override_options..............: ${smtp_active_value}"
echo " AmaViS receive_override_options...............: ${amavis_active_value:-<not set>}"
echo ""
if ! ask_yes_no "einverstanden" "no" ; then
warn "Activation cancelled by user. Nothing was changed."
clean_up 0
fi
# ----------
# Prepare rollback
# ----------
echononl "Snapshot disabled SRS service states.."
if snapshot_service_states ; then
echo_ok
else
echo_failed
fatal "Cannot safely snapshot disabled SRS services. Activation was not attempted."
fi
ACTIVATION_BACKUP_DIR="/root/postfix-srs-activation-${backup_date}"
echononl "Create activation backup directory.."
if mkdir -m 0700 "$ACTIVATION_BACKUP_DIR" > "$log_file" 2>&1 ; then
echo_ok
printf ' Directory: %s\n' "$ACTIVATION_BACKUP_DIR"
else
echo_failed
fatal "$(cat "$log_file")"
fi
echononl "Backup '${POSTFIX_MAIN_CF}'.."
if cp -a "$POSTFIX_MAIN_CF" "${ACTIVATION_BACKUP_DIR}/main.cf" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
echononl "Backup '${POSTFIX_MASTER_CF}'.."
if cp -a "$POSTFIX_MASTER_CF" "${ACTIVATION_BACKUP_DIR}/master.cf" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
echononl "Backup existing systemd SRS drop-ins.."
if snapshot_systemd_dropins > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
echononl "Recheck primary Postfix service '${POSTFIX_SERVICE}' is active.."
if systemctl is-active --quiet "$POSTFIX_SERVICE" ; then
echo_ok
else
echo_failed
fatal "Primary Postfix became inactive. Activation was not attempted."
fi
ACTIVATION_CHANGES_STARTED=true
# ----------
# Activate Postfix integration
# ----------
blank_line
echo -e "\033[37m\033[1mActivate selective SRS Postfix integration..\033[m"
blank_line
echononl "Add managed SRS block to '${POSTFIX_MAIN_CF}'.."
if append_main_cf_managed_block > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal_with_activation_rollback "Could not add managed SRS block to '${POSTFIX_MAIN_CF}'."
fi
echononl "Add managed SRS service block to '${POSTFIX_MASTER_CF}'.."
if append_master_cf_managed_block > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal_with_activation_rollback "Could not add managed SRS block to '${POSTFIX_MASTER_CF}'."
fi
echononl "Add incoming SRS virtual alias domain and reverse map.."
if srs_alias_tool add > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal_with_activation_rollback "Could not add tracked virtual alias items: $(cat "$log_file")"
fi
echononl "Set port 25 receive_override_options.."
if update_master_service_option \
smtp \
receive_override_options \
"$smtp_active_value" > "$log_file" 2>&1
then
echo_ok
else
echo_failed
fatal_with_activation_rollback "Could not update port 25 receive_override_options."
fi
echononl "Set AmaViS reinjection receive_override_options.."
if update_master_service_option \
localhost:10025 \
receive_override_options \
"$amavis_active_value" > "$log_file" 2>&1
then
echo_ok
else
echo_failed
fatal_with_activation_rollback "Could not update AmaViS reinjection receive_override_options."
fi
echononl "Check Postfix configuration.."
if postfix check > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal_with_activation_rollback "Postfix configuration check failed. $(cat "$log_file")"
fi
# ----------
# Install systemd dependencies and start/enable SRS runtime services
# ----------
blank_line
echo -e "\033[37m\033[1mStart selective SRS runtime services..\033[m"
blank_line
echononl "Install systemd SRS dependency drop-ins.."
if write_srs_systemd_dropins > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal_with_activation_rollback "Could not install systemd SRS dependency drop-ins. $(cat "$log_file")"
fi
for _service in \
"$POSTSRSD_SERVICE" \
"$SRS_REVERSE_MAP_SERVICE" \
"$SRS_DELIVERY_SERVICE"
do
echononl "Enable systemd service '${_service}'.."
if systemctl enable "$_service" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal_with_activation_rollback "Could not enable systemd service '${_service}'. $(cat "$log_file")"
fi
echononl "Start systemd service '${_service}'.."
if systemctl start "$_service" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal_with_activation_rollback "Could not start systemd service '${_service}'. $(cat "$log_file")"
fi
done
# ----------
# Verify listeners before Postfix reload
# ----------
for _endpoint in \
"PostSRSd socketmap|${POSTSRSD_SOCKET_HOST}|${POSTSRSD_SOCKET_PORT}" \
"SRS reverse socketmap|${SRS_REVERSE_SOCKET_HOST}|${SRS_REVERSE_SOCKET_PORT}" \
"SRS reinjection listener|${SRS_REINJECT_HOST}|${SRS_REINJECT_PORT}" \
"SRS reverse listener|${SRS_REVERSE_HOST}|${SRS_REVERSE_PORT}"
do
IFS='|' read -r _label _host _port <<< "$_endpoint"
echononl "Verify ${_label} on ${_host}:${_port}.."
if port_is_listening "$_host" "$_port" ; then
echo_ok
else
echo_failed
fatal_with_activation_rollback "${_label} is not listening on ${_host}:${_port}."
fi
done
# ----------
# Reload main Postfix
# ----------
blank_line
echononl "Reload main Postfix service '${POSTFIX_SERVICE}'.."
if systemctl reload "$POSTFIX_SERVICE" > "$log_file" 2>&1 ; then
POSTFIX_RELOADED=true
echo_ok
else
echo_failed
fatal_with_activation_rollback "Could not reload '${POSTFIX_SERVICE}'. $(cat "$log_file")"
fi
# ----------
# Final verification
# ----------
blank_line
echo -e "\033[37m\033[1mVerify activated selective SRS configuration..\033[m"
blank_line
verification_ok=true
echononl "Verify managed main.cf block.."
if check_managed_block_markers \
"$POSTFIX_MAIN_CF" \
"$SRS_MAIN_CF_BEGIN_MARKER" \
"$SRS_MAIN_CF_END_MARKER"
then
echo_ok
else
echo_failed
verification_ok=false
fi
echononl "Verify managed master.cf block.."
if check_managed_block_markers \
"$POSTFIX_MASTER_CF" \
"$SRS_MASTER_CF_BEGIN_MARKER" \
"$SRS_MASTER_CF_END_MARKER"
then
echo_ok
else
echo_failed
verification_ok=false
fi
echononl "Verify 'default_transport = srs-forward'.."
if [[ "$(main_cf_explicit_value default_transport)" == "srs-forward" ]]; then
echo_ok
else
echo_failed
verification_ok=false
fi
echononl "Verify SRS recipient canonical map.."
if [[ "$(main_cf_explicit_value recipient_canonical_maps)" == \
"socketmap:inet:${SRS_REVERSE_SOCKET_HOST}:${SRS_REVERSE_SOCKET_PORT}:reverse" ]]
then
echo_ok
else
echo_failed
verification_ok=false
fi
echononl "Verify incoming SRS alias ownership.."
if [[ "$(srs_alias_tool status 2>"$log_file")" == 'managed' ]]; then
echo_ok
else
echo_failed
verification_ok=false
fi
echononl "Verify 'srs-forward' pipe service.."
if master_srs_forward_present ; then
echo_ok
else
echo_failed
verification_ok=false
fi
echononl "Verify port 25 receive_override_options.."
if [[ "$(master_service_option_value smtp receive_override_options)" == "$smtp_active_value" ]]; then
echo_ok
else
echo_failed
verification_ok=false
fi
echononl "Verify AmaViS reinjection receive_override_options.."
if [[ "$(master_service_option_value localhost:10025 receive_override_options)" == "$amavis_active_value" ]]; then
echo_ok
else
echo_failed
verification_ok=false
fi
for _service in \
"$POSTSRSD_SERVICE" \
"$SRS_REVERSE_MAP_SERVICE" \
"$SRS_DELIVERY_SERVICE"
do
echononl "Verify systemd service '${_service}' is active.."
if read_srs_service_state "$_service" &&
[[ "$SRS_SERVICE_ACTIVE_STATE" == "active" ]] &&
[[ "$SRS_SERVICE_ENABLED_STATE" != "disabled" ]]
then
echo_ok
else
echo_failed
verification_ok=false
fi
done
for _endpoint in \
"PostSRSd socketmap|${POSTSRSD_SOCKET_HOST}|${POSTSRSD_SOCKET_PORT}" \
"SRS reverse socketmap|${SRS_REVERSE_SOCKET_HOST}|${SRS_REVERSE_SOCKET_PORT}" \
"SRS reinjection listener|${SRS_REINJECT_HOST}|${SRS_REINJECT_PORT}" \
"SRS reverse listener|${SRS_REVERSE_HOST}|${SRS_REVERSE_PORT}"
do
IFS='|' read -r _label _host _port <<< "$_endpoint"
echononl "Verify ${_label} remains listening on ${_host}:${_port}.."
if port_is_listening "$_host" "$_port" ; then
echo_ok
else
echo_failed
verification_ok=false
fi
done
echononl "Verify primary Postfix remains active.."
if systemctl is-active --quiet "$POSTFIX_SERVICE" ; then
echo_ok
else
echo_failed
verification_ok=false
fi
echononl "Final Postfix configuration check.."
if postfix check > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
verification_ok=false
fi
if ! $verification_ok ; then
fatal_with_activation_rollback "Final selective SRS verification failed."
fi
# ----------
# Success
# ----------
ACTIVATION_CHANGES_STARTED=false
blank_line
info "Selective SRS was successfully activated."
echo " Current selective SRS state....................: ENABLED"
echo " Activation backup..............................: ${ACTIVATION_BACKUP_DIR}"
echo ""
clean_up 0