fix: check-for-changes.sh should not fall out of sync with shared logic (#2260)

Removes duplicate logic from `check-for-changes.sh` that is used/maintained elsewhere to avoid risk of problems, as this code is already starting to diverge / rot.

---

Previously the change detection support has had code added for rebuilding config upon change detection which is the same as code run during startup scripts. Unfortunately over time this has fallen out of sync. Mostly the startup scripts would get maintenance and the contributor and reviewers may not have been aware of the duplicate code handled by `check-for-changes.sh`.

That code was starting to diverge in addition to some changes in structure (_eg: relay host logic seems interleaved here vs separated out in startup scripts_). I wanted to address this before it risks becoming a much bigger headache.

Rather than bloat `helper-functions.sh` further, I've added a `helpers/` folder extracting relevant common logic between startup scripts and `changedetector`. If you want to follow that process I've kept scoped commits to make those diffs easier. Some minor changes/improvements were added but nothing significant.

---

- chore: Extract relay host logic to new `relay.sh` helper
- chore: Extract `/etc/postfix/sasl_passwd` logic to new `sasl.sh` helper
- chore: Extract `postfix-accounts.cf` logic to new `accounts.sh` helper
- chore: Extract `/etc/aliases` logic to new `aliases.sh` helper
- chore: Extract `/etc/postfix/vhost` logic to new `postfix.sh` helper

- chore: Add inline docs for Postfix configs
> These are possibly more verbose than needed and can be reduced at a later stage.
> They are helpful during this refactor process while investigating that everything is handled correctly.

`accounts.sh`: 
- Add note regarding potential bug for bare domain setups with `/etc/postfix/vhost` and `mydestination` sharing same domain value.

`relay.sh`: 
- Remove the tabs for a single space delimiter, revised associated comment.
- Add PR reference for original `_populate_relayhost_map` implementation which has some useful details.


Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
Co-authored-by: Casper <casperklein@users.noreply.github.com>
This commit is contained in:
Brennan Kinney 2021-11-21 09:33:49 +13:00 committed by GitHub
parent ae70142d8f
commit 5254f7c658
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 501 additions and 439 deletions

View file

@ -315,132 +315,11 @@ function _setup_dovecot_quota
function _setup_dovecot_local_user
{
_notify 'task' 'Setting up Dovecot Local User'
: >/etc/postfix/vmailbox
: >/etc/dovecot/userdb
if [[ -f /tmp/docker-mailserver/postfix-accounts.cf ]] && [[ ${ENABLE_LDAP} -ne 1 ]]
_create_accounts
if [[ ! -f /tmp/docker-mailserver/postfix-accounts.cf ]]
then
_notify 'inf' "Checking file line endings"
sed -i 's|\r||g' /tmp/docker-mailserver/postfix-accounts.cf
_notify 'inf' "Regenerating postfix user list"
echo "# WARNING: this file is auto-generated. Modify /tmp/docker-mailserver/postfix-accounts.cf to edit the user list." > /etc/postfix/vmailbox
# checking that /tmp/docker-mailserver/postfix-accounts.cf ends with a newline
# shellcheck disable=SC1003
sed -i -e '$a\' /tmp/docker-mailserver/postfix-accounts.cf
chown dovecot:dovecot /etc/dovecot/userdb
chmod 640 /etc/dovecot/userdb
sed -i -e '/\!include auth-ldap\.conf\.ext/s/^/#/' /etc/dovecot/conf.d/10-auth.conf
sed -i -e '/\!include auth-passwdfile\.inc/s/^#//' /etc/dovecot/conf.d/10-auth.conf
# creating users ; 'pass' is encrypted
# comments and empty lines are ignored
local LOGIN PASS USER_ATTRIBUTES
while IFS=$'|' read -r LOGIN PASS USER_ATTRIBUTES
do
# Setting variables for better readability
USER=$(echo "${LOGIN}" | cut -d @ -f1)
DOMAIN=$(echo "${LOGIN}" | cut -d @ -f2)
# test if user has a defined quota
if [[ -f /tmp/docker-mailserver/dovecot-quotas.cf ]]
then
declare -a USER_QUOTA
IFS=':' read -r -a USER_QUOTA < <(grep "${USER}@${DOMAIN}:" -i /tmp/docker-mailserver/dovecot-quotas.cf)
if [[ ${#USER_QUOTA[@]} -eq 2 ]]
then
USER_ATTRIBUTES="${USER_ATTRIBUTES:+${USER_ATTRIBUTES} }userdb_quota_rule=*:bytes=${USER_QUOTA[1]}"
fi
fi
if [[ -z ${USER_ATTRIBUTES} ]]
then
_notify 'inf' "Creating user '${USER}' for domain '${DOMAIN}'"
else
_notify 'inf' "Creating user '${USER}' for domain '${DOMAIN}' with attributes '${USER_ATTRIBUTES}'"
fi
echo "${LOGIN} ${DOMAIN}/${USER}/" >> /etc/postfix/vmailbox
# Dovecot's userdb has the following format
# user:password:uid:gid:(gecos):home:(shell):extra_fields
echo \
"${LOGIN}:${PASS}:5000:5000::/var/mail/${DOMAIN}/${USER}::${USER_ATTRIBUTES}" \
>>/etc/dovecot/userdb
mkdir -p "/var/mail/${DOMAIN}/${USER}"
# copy user provided sieve file, if present
if [[ -e "/tmp/docker-mailserver/${LOGIN}.dovecot.sieve" ]]
then
cp "/tmp/docker-mailserver/${LOGIN}.dovecot.sieve" "/var/mail/${DOMAIN}/${USER}/.dovecot.sieve"
fi
echo "${DOMAIN}" >> /tmp/vhost.tmp
done < <(grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-accounts.cf)
# see https://github.com/docker-mailserver/docker-mailserver/pull/2248#issuecomment-953313852
# for more details on this section
if [[ -f /tmp/docker-mailserver/postfix-virtual.cf ]] && [[ ${ENABLE_QUOTAS} -eq 1 ]]
then
# adding aliases to Dovecot's userdb
# ${REAL_FQUN} is a user's fully-qualified username
local ALIAS REAL_FQUN
while read -r ALIAS REAL_FQUN
do
# ignore comments
[[ ${ALIAS} == \#* ]] && continue
# alias is assumed to not be a proper e-mail
# these aliases do not need to be added to Dovecot's userdb
[[ ! ${ALIAS} == *@* ]] && continue
# clear possibly already filled arrays
# do not remove the following line of code
unset REAL_ACC USER_QUOTA
declare -a REAL_ACC USER_QUOTA
local REAL_USERNAME REAL_DOMAINNAME
REAL_USERNAME=$(cut -d '@' -f 1 <<< "${REAL_FQUN}")
REAL_DOMAINNAME=$(cut -d '@' -f 2 <<< "${REAL_FQUN}")
if ! grep -q "${REAL_FQUN}" /tmp/docker-mailserver/postfix-accounts.cf
then
_notify 'inf' "Alias '${ALIAS}' is non-local (or mapped to a non-existing account) and will not be added to Dovecot's userdb"
continue
fi
_notify 'inf' "Adding alias '${ALIAS}' for user '${REAL_FQUN}' to Dovecot's userdb"
# ${REAL_ACC[0]} => real account name (e-mail address) == ${REAL_FQUN}
# ${REAL_ACC[1]} => password hash
# ${REAL_ACC[2]} => optional user attributes
IFS='|' read -r -a REAL_ACC < <(grep "${REAL_FQUN}" /tmp/docker-mailserver/postfix-accounts.cf)
if [[ -z ${REAL_ACC[1]} ]]
then
dms_panic__misconfigured 'postfix-accounts.cf' 'alias configuration'
fi
# test if user has a defined quota
if [[ -f /tmp/docker-mailserver/dovecot-quotas.cf ]]
then
IFS=':' read -r -a USER_QUOTA < <(grep "${REAL_FQUN}:" -i /tmp/docker-mailserver/dovecot-quotas.cf)
if [[ ${#USER_QUOTA[@]} -eq 2 ]]
then
REAL_ACC[2]="${REAL_ACC[2]:+${REAL_ACC[2]} }userdb_quota_rule=*:bytes=${USER_QUOTA[1]}"
fi
fi
echo \
"${ALIAS}:${REAL_ACC[1]}:5000:5000::/var/mail/${REAL_DOMAINNAME}/${REAL_USERNAME}::${REAL_ACC[2]:-}" \
>> /etc/dovecot/userdb
done < /tmp/docker-mailserver/postfix-virtual.cf
fi
else
_notify 'inf' "'/tmp/docker-mailserver/postfix-accounts.cf' is not provided. No mail account created."
fi
@ -758,57 +637,7 @@ EOF
function _setup_postfix_aliases
{
_notify 'task' 'Setting up Postfix Aliases'
: >/etc/postfix/virtual
: >/etc/postfix/regexp
if [[ -f /tmp/docker-mailserver/postfix-virtual.cf ]]
then
# fixing old virtual user file
if grep -q ",$" /tmp/docker-mailserver/postfix-virtual.cf
then
sed -i -e "s|, |,|g" -e "s|,$||g" /tmp/docker-mailserver/postfix-virtual.cf
fi
cp -f /tmp/docker-mailserver/postfix-virtual.cf /etc/postfix/virtual
# the `to` is important, don't delete it
# shellcheck disable=SC2034
while read -r FROM TO
do
UNAME=$(echo "${FROM}" | cut -d @ -f1)
DOMAIN=$(echo "${FROM}" | cut -d @ -f2)
# if they are equal it means the line looks like: "user1 other@domain.tld"
[[ ${UNAME} != "${DOMAIN}" ]] && echo "${DOMAIN}" >>/tmp/vhost.tmp
done < <(grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-virtual.cf || true)
else
_notify 'inf' "Warning '/tmp/docker-mailserver/postfix-virtual.cf' is not provided. No mail alias/forward created."
fi
if [[ -f /tmp/docker-mailserver/postfix-regexp.cf ]]
then
_notify 'inf' "Adding regexp alias file postfix-regexp.cf"
cp -f /tmp/docker-mailserver/postfix-regexp.cf /etc/postfix/regexp
sed -i -E \
's|virtual_alias_maps(.*)|virtual_alias_maps\1 pcre:/etc/postfix/regexp|g' \
/etc/postfix/main.cf
fi
_notify 'inf' 'Configuring root alias'
echo "root: ${POSTMASTER_ADDRESS}" > /etc/aliases
if [[ -f /tmp/docker-mailserver/postfix-aliases.cf ]]
then
cat /tmp/docker-mailserver/postfix-aliases.cf >>/etc/aliases
else
_notify 'inf' "'/tmp/docker-mailserver/postfix-aliases.cf' is not provided, it will be auto created."
: >/tmp/docker-mailserver/postfix-aliases.cf
fi
postalias /etc/aliases
_create_aliases
}
function _setup_SRS
@ -1262,15 +1091,7 @@ function _setup_ssl
function _setup_postfix_vhost
{
_notify 'task' "Setting up Postfix vhost"
if [[ -f /tmp/vhost.tmp ]]
then
sort < /tmp/vhost.tmp | uniq > /etc/postfix/vhost
rm /tmp/vhost.tmp
elif [[ ! -f /etc/postfix/vhost ]]
then
touch /etc/postfix/vhost
fi
_create_postfix_vhost
}
function _setup_inet_protocols
@ -1396,90 +1217,19 @@ function _setup_postfix_sasl_password
_notify 'task' 'Setting up Postfix SASL Password'
# support general SASL password
rm -f /etc/postfix/sasl_passwd
if [[ -n ${SASL_PASSWD} ]]
then
echo "${SASL_PASSWD}" >> /etc/postfix/sasl_passwd
fi
_sasl_passwd_create
# install SASL passwords
if [[ -f /etc/postfix/sasl_passwd ]]
then
chown root:root /etc/postfix/sasl_passwd
chmod 0600 /etc/postfix/sasl_passwd
_notify 'inf' "Loaded SASL_PASSWD"
else
_notify 'inf' "Warning: 'SASL_PASSWD' is not provided. /etc/postfix/sasl_passwd not created."
_notify 'inf' "Warning: 'SASL_PASSWD' was not provided. /etc/postfix/sasl_passwd not created."
fi
}
function _setup_postfix_default_relay_host
{
_notify 'task' 'Applying default relay host to Postfix'
_notify 'inf' "Applying default relay host ${DEFAULT_RELAY_HOST} to /etc/postfix/main.cf"
postconf -e "relayhost = ${DEFAULT_RELAY_HOST}"
}
function _setup_postfix_relay_hosts
{
_notify 'task' 'Setting up Postfix Relay Hosts'
[[ -z ${RELAY_PORT} ]] && RELAY_PORT=25
# shellcheck disable=SC2153
_notify 'inf' "Setting up outgoing email relaying via ${RELAY_HOST}:${RELAY_PORT}"
# setup /etc/postfix/sasl_passwd
# --
# @domain1.com postmaster@domain1.com:your-password-1
# @domain2.com postmaster@domain2.com:your-password-2
# @domain3.com postmaster@domain3.com:your-password-3
#
# [smtp.mailgun.org]:587 postmaster@domain2.com:your-password-2
if [[ -f /tmp/docker-mailserver/postfix-sasl-password.cf ]]
then
_notify 'inf' "Adding relay authentication from postfix-sasl-password.cf"
while read -r LINE
do
if ! echo "${LINE}" | grep -q -e "^\s*#"
then
echo "${LINE}" >> /etc/postfix/sasl_passwd
fi
done < /tmp/docker-mailserver/postfix-sasl-password.cf
fi
# add default relay
if [[ -n ${RELAY_USER} ]] && [[ -n ${RELAY_PASSWORD} ]]
then
echo "[${RELAY_HOST}]:${RELAY_PORT} ${RELAY_USER}:${RELAY_PASSWORD}" >> /etc/postfix/sasl_passwd
else
if [[ ! -f /tmp/docker-mailserver/postfix-sasl-password.cf ]]
then
_notify 'warn' "No relay auth file found and no default set"
fi
fi
if [[ -f /etc/postfix/sasl_passwd ]]
then
chown root:root /etc/postfix/sasl_passwd
chmod 0600 /etc/postfix/sasl_passwd
fi
# end /etc/postfix/sasl_passwd
_populate_relayhost_map
postconf -e \
"smtp_sasl_auth_enable = yes" \
"smtp_sasl_security_options = noanonymous" \
"smtp_sasl_password_maps = texthash:/etc/postfix/sasl_passwd" \
"smtp_tls_security_level = encrypt" \
"smtp_tls_note_starttls_offer = yes" \
"smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt" \
"sender_dependent_relayhost_maps = texthash:/etc/postfix/relayhost_map" \
"smtp_sender_dependent_authentication = yes"
_setup_relayhost
}
function _setup_postfix_dhparam