2020-10-21 16:16:32 +00:00
|
|
|
|
#! /bin/bash
|
2019-08-07 00:24:56 +00:00
|
|
|
|
|
2021-01-16 09:16:05 +00:00
|
|
|
|
DMS_DEBUG="${DMS_DEBUG:=0}"
|
2020-09-05 14:19:12 +00:00
|
|
|
|
|
2021-01-16 09:16:05 +00:00
|
|
|
|
# ? ––––––––––––––––––––––––––––––––––––––––––––– BIN HELPER
|
|
|
|
|
|
|
|
|
|
function errex
|
|
|
|
|
{
|
|
|
|
|
echo "${@}" 1>&2
|
|
|
|
|
exit 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function escape
|
|
|
|
|
{
|
|
|
|
|
echo "${1//./\\.}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ? ––––––––––––––––––––––––––––––––––––––––––––– IP & CIDR
|
2020-09-05 14:19:12 +00:00
|
|
|
|
|
2020-10-02 13:45:57 +00:00
|
|
|
|
function _mask_ip_digit
|
2020-09-05 14:19:12 +00:00
|
|
|
|
{
|
|
|
|
|
if [[ ${1} -ge 8 ]]
|
|
|
|
|
then
|
2020-06-30 20:43:22 +00:00
|
|
|
|
MASK=255
|
2020-09-05 14:19:12 +00:00
|
|
|
|
elif [[ ${1} -le 0 ]]
|
|
|
|
|
then
|
|
|
|
|
MASK=0
|
2020-06-30 20:43:22 +00:00
|
|
|
|
else
|
2020-09-05 14:19:12 +00:00
|
|
|
|
VALUES=(0 128 192 224 240 248 252 254 255)
|
2020-09-06 10:27:40 +00:00
|
|
|
|
MASK=${VALUES[${1}]}
|
2020-06-30 20:43:22 +00:00
|
|
|
|
fi
|
2020-09-05 14:19:12 +00:00
|
|
|
|
|
|
|
|
|
local DVAL=${2}
|
|
|
|
|
((DVAL&=MASK))
|
|
|
|
|
|
2020-09-06 10:27:40 +00:00
|
|
|
|
echo "${DVAL}"
|
2019-08-07 00:24:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-05 14:19:12 +00:00
|
|
|
|
# Transforms a specific IP with CIDR suffix
|
|
|
|
|
# like 1.2.3.4/16 to subnet with cidr suffix
|
|
|
|
|
# like 1.2.0.0/16.
|
|
|
|
|
# Assumes correct IP and subnet are provided.
|
2020-10-02 13:45:57 +00:00
|
|
|
|
function _sanitize_ipv4_to_subnet_cidr
|
2020-09-05 14:19:12 +00:00
|
|
|
|
{
|
|
|
|
|
local DIGIT_PREFIX_LENGTH="${1#*/}"
|
|
|
|
|
|
2020-09-26 13:11:52 +00:00
|
|
|
|
declare -a MASKED_DIGITS DIGITS
|
2020-09-06 10:27:40 +00:00
|
|
|
|
IFS='.' ; read -r -a DIGITS < <(echo "${1%%/*}") ; unset IFS
|
2020-09-05 14:19:12 +00:00
|
|
|
|
|
|
|
|
|
for ((i = 0 ; i < 4 ; i++))
|
|
|
|
|
do
|
2020-09-06 10:27:40 +00:00
|
|
|
|
MASKED_DIGITS[i]=$(_mask_ip_digit "${DIGIT_PREFIX_LENGTH}" "${DIGITS[i]}")
|
2020-09-05 14:19:12 +00:00
|
|
|
|
DIGIT_PREFIX_LENGTH=$((DIGIT_PREFIX_LENGTH - 8))
|
2020-06-30 20:43:22 +00:00
|
|
|
|
done
|
2019-08-07 00:24:56 +00:00
|
|
|
|
|
2020-09-05 14:19:12 +00:00
|
|
|
|
echo "${MASKED_DIGITS[0]}.${MASKED_DIGITS[1]}.${MASKED_DIGITS[2]}.${MASKED_DIGITS[3]}/${1#*/}"
|
2020-06-30 20:43:22 +00:00
|
|
|
|
}
|
2020-09-05 14:19:12 +00:00
|
|
|
|
export -f _sanitize_ipv4_to_subnet_cidr
|
|
|
|
|
|
2021-01-16 09:16:05 +00:00
|
|
|
|
# ? ––––––––––––––––––––––––––––––––––––––––––––– ACME
|
2020-09-05 14:19:12 +00:00
|
|
|
|
|
2020-10-02 13:45:57 +00:00
|
|
|
|
function _extract_certs_from_acme
|
2020-09-05 14:19:12 +00:00
|
|
|
|
{
|
|
|
|
|
local KEY
|
|
|
|
|
# shellcheck disable=SC2002
|
2020-07-19 21:57:16 +00:00
|
|
|
|
KEY=$(cat /etc/letsencrypt/acme.json | python -c "
|
|
|
|
|
import sys,json
|
|
|
|
|
acme = json.load(sys.stdin)
|
|
|
|
|
for key, value in acme.items():
|
|
|
|
|
certs = value['Certificates']
|
2020-12-06 19:29:12 +00:00
|
|
|
|
if certs is not None:
|
|
|
|
|
for cert in certs:
|
|
|
|
|
if 'domain' in cert and 'key' in cert:
|
|
|
|
|
if 'main' in cert['domain'] and cert['domain']['main'] == '${1}' or 'sans' in cert['domain'] and '${1}' in cert['domain']['sans']:
|
|
|
|
|
print cert['key']
|
|
|
|
|
break
|
2020-07-19 21:57:16 +00:00
|
|
|
|
")
|
2020-09-05 14:19:12 +00:00
|
|
|
|
|
|
|
|
|
local CERT
|
|
|
|
|
# shellcheck disable=SC2002
|
2020-07-19 21:57:16 +00:00
|
|
|
|
CERT=$(cat /etc/letsencrypt/acme.json | python -c "
|
|
|
|
|
import sys,json
|
|
|
|
|
acme = json.load(sys.stdin)
|
|
|
|
|
for key, value in acme.items():
|
|
|
|
|
certs = value['Certificates']
|
2020-12-06 19:29:12 +00:00
|
|
|
|
if certs is not None:
|
|
|
|
|
for cert in certs:
|
|
|
|
|
if 'domain' in cert and 'certificate' in cert:
|
|
|
|
|
if 'main' in cert['domain'] and cert['domain']['main'] == '${1}' or 'sans' in cert['domain'] and '${1}' in cert['domain']['sans']:
|
|
|
|
|
print cert['certificate']
|
|
|
|
|
break
|
2020-07-19 21:57:16 +00:00
|
|
|
|
")
|
2020-06-30 20:43:22 +00:00
|
|
|
|
|
2020-09-05 14:19:12 +00:00
|
|
|
|
if [[ -n "${KEY}${CERT}" ]]
|
|
|
|
|
then
|
|
|
|
|
mkdir -p "/etc/letsencrypt/live/${HOSTNAME}/"
|
|
|
|
|
|
2020-09-06 10:27:40 +00:00
|
|
|
|
echo "${KEY}" | base64 -d >/etc/letsencrypt/live/"${HOSTNAME}"/key.pem || exit 1
|
|
|
|
|
echo "${CERT}" | base64 -d >/etc/letsencrypt/live/"${HOSTNAME}"/fullchain.pem || exit 1
|
|
|
|
|
echo "Cert found in /etc/letsencrypt/acme.json for ${1}"
|
2020-09-05 14:19:12 +00:00
|
|
|
|
|
2020-06-30 20:43:22 +00:00
|
|
|
|
return 0
|
|
|
|
|
else
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
}
|
2020-09-05 14:19:12 +00:00
|
|
|
|
export -f _extract_certs_from_acme
|
|
|
|
|
|
2021-01-16 09:16:05 +00:00
|
|
|
|
# ? ––––––––––––––––––––––––––––––––––––––––––––– Notifications
|
2020-08-24 20:08:11 +00:00
|
|
|
|
|
2020-10-02 13:45:57 +00:00
|
|
|
|
function _notify
|
2020-09-05 14:19:12 +00:00
|
|
|
|
{
|
2021-01-16 09:16:05 +00:00
|
|
|
|
local FINAL_MSG=''
|
|
|
|
|
local MSG="${2:-}"
|
|
|
|
|
local TYPE="${1:-}"
|
|
|
|
|
|
|
|
|
|
case "${TYPE}" in
|
|
|
|
|
'none' ) FINAL_MSG=' ' ;;
|
|
|
|
|
'tasklog' ) FINAL_MSG="[ \e[0;92mTASKLOG\e[0m ] ${MSG}" ;; # light green
|
|
|
|
|
'warn' ) FINAL_MSG="[ \e[0;93mWARNING\e[0m ] ${MSG}" ;; # light yellow
|
|
|
|
|
'err' ) FINAL_MSG="[ \e[0;31mERROR\e[0m ] ${MSG}" ;; # light red
|
|
|
|
|
'fatal' ) FINAL_MSG="[ \e[0;91mFATAL\e[0m ] ${MSG}" ;; # red
|
|
|
|
|
'inf' ) [[ ${DMS_DEBUG} -eq 1 ]] && FINAL_MSG="[[ \e[0;34mINFO\e[0m ]] ${MSG}" ;; # light blue
|
|
|
|
|
'task' ) [[ ${DMS_DEBUG} -eq 1 ]] && FINAL_MSG="[[ \e[0;37mTASK\e[0m ]] ${MSG}" ;; # light grey
|
|
|
|
|
* ) ;;
|
2020-08-24 20:08:11 +00:00
|
|
|
|
esac
|
|
|
|
|
|
2021-01-16 09:16:05 +00:00
|
|
|
|
[[ -n ${FINAL_MSG} ]] && echo "-e${3:-}" "${FINAL_MSG}"
|
2020-08-24 20:08:11 +00:00
|
|
|
|
}
|
2020-09-05 14:53:36 +00:00
|
|
|
|
export -f _notify
|
2020-09-05 14:19:12 +00:00
|
|
|
|
|
2021-01-16 09:16:05 +00:00
|
|
|
|
# ? ––––––––––––––––––––––––––––––––––––––––––––– Relay Host Map
|
2020-08-24 20:08:11 +00:00
|
|
|
|
|
|
|
|
|
# setup /etc/postfix/relayhost_map
|
|
|
|
|
# --
|
|
|
|
|
# @domain1.com [smtp.mailgun.org]:587
|
|
|
|
|
# @domain2.com [smtp.mailgun.org]:587
|
|
|
|
|
# @domain3.com [smtp.mailgun.org]:587
|
2020-10-02 13:45:57 +00:00
|
|
|
|
function _populate_relayhost_map
|
2020-09-05 14:19:12 +00:00
|
|
|
|
{
|
2020-10-06 12:45:55 +00:00
|
|
|
|
: >/etc/postfix/relayhost_map
|
2020-08-24 20:08:11 +00:00
|
|
|
|
chown root:root /etc/postfix/relayhost_map
|
|
|
|
|
chmod 0600 /etc/postfix/relayhost_map
|
|
|
|
|
|
2020-09-05 14:19:12 +00:00
|
|
|
|
if [[ -f /tmp/docker-mailserver/postfix-relaymap.cf ]]
|
|
|
|
|
then
|
2020-09-05 14:53:36 +00:00
|
|
|
|
_notify 'inf' "Adding relay mappings from postfix-relaymap.cf"
|
2020-09-05 14:19:12 +00:00
|
|
|
|
# keep lines which are not a comment *and* have a destination.
|
|
|
|
|
sed -n '/^\s*[^#[:space:]]\S*\s\+\S/p' /tmp/docker-mailserver/postfix-relaymap.cf >> /etc/postfix/relayhost_map
|
2020-08-24 20:08:11 +00:00
|
|
|
|
fi
|
2020-09-05 14:19:12 +00:00
|
|
|
|
|
2020-08-24 20:53:54 +00:00
|
|
|
|
{
|
2020-09-05 14:19:12 +00:00
|
|
|
|
# note: won't detect domains when lhs has spaces (but who does that?!)
|
2020-08-24 20:53:54 +00:00
|
|
|
|
sed -n '/^\s*[^#[:space:]]/ s/^[^@|]*@\([^|]\+\)|.*$/\1/p' /tmp/docker-mailserver/postfix-accounts.cf
|
2020-09-05 14:19:12 +00:00
|
|
|
|
|
|
|
|
|
[ -f /tmp/docker-mailserver/postfix-virtual.cf ] && sed -n '/^\s*[^#[:space:]]/ s/^\s*[^@[:space:]]*@\(\S\+\)\s.*/\1/p' /tmp/docker-mailserver/postfix-virtual.cf
|
|
|
|
|
} | while read -r domain
|
|
|
|
|
do
|
|
|
|
|
# domain not already present *and* not ignored
|
|
|
|
|
if ! grep -q -e "^@${domain}\b" /etc/postfix/relayhost_map && ! grep -qs -e "^\s*@${domain}\s*$" /tmp/docker-mailserver/postfix-relaymap.cf
|
|
|
|
|
then
|
2020-09-05 14:53:36 +00:00
|
|
|
|
_notify 'inf' "Adding relay mapping for ${domain}"
|
2020-09-06 10:27:40 +00:00
|
|
|
|
echo "@${domain} [${RELAY_HOST}]:${RELAY_PORT}" >> /etc/postfix/relayhost_map
|
2020-08-24 20:08:11 +00:00
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
}
|
2020-09-05 14:19:12 +00:00
|
|
|
|
export -f _populate_relayhost_map
|
|
|
|
|
|
2021-01-16 09:16:05 +00:00
|
|
|
|
# ? ––––––––––––––––––––––––––––––––––––––––––––– File Checksums
|
2020-08-24 20:08:11 +00:00
|
|
|
|
|
2020-09-05 14:19:12 +00:00
|
|
|
|
# file storing the checksums of the monitored files.
|
|
|
|
|
# shellcheck disable=SC2034
|
2020-08-24 18:46:50 +00:00
|
|
|
|
CHKSUM_FILE=/tmp/docker-mailserver-config-chksum
|
|
|
|
|
|
|
|
|
|
# Compute checksums of monitored files.
|
2020-10-02 13:45:57 +00:00
|
|
|
|
function _monitored_files_checksums
|
2020-09-05 14:19:12 +00:00
|
|
|
|
{
|
2020-08-24 18:46:50 +00:00
|
|
|
|
(
|
2020-09-05 14:19:12 +00:00
|
|
|
|
cd /tmp/docker-mailserver || exit 1
|
2020-08-24 18:46:50 +00:00
|
|
|
|
exec sha512sum 2>/dev/null -- \
|
2020-09-05 14:19:12 +00:00
|
|
|
|
postfix-accounts.cf \
|
|
|
|
|
postfix-virtual.cf \
|
|
|
|
|
postfix-aliases.cf \
|
|
|
|
|
dovecot-quotas.cf \
|
|
|
|
|
/etc/letsencrypt/acme.json \
|
2020-09-06 10:27:40 +00:00
|
|
|
|
"/etc/letsencrypt/live/${HOSTNAME}/key.pem" \
|
2020-11-16 14:49:35 +00:00
|
|
|
|
"/etc/letsencrypt/live/${HOSTNAME}/privkey.pem" \
|
2020-09-06 10:27:40 +00:00
|
|
|
|
"/etc/letsencrypt/live/${HOSTNAME}/fullchain.pem"
|
2020-08-24 18:46:50 +00:00
|
|
|
|
)
|
|
|
|
|
}
|
2020-09-05 14:19:12 +00:00
|
|
|
|
export -f _monitored_files_checksums
|